第二章 词法结构
2.1字符集
Unicode
2.1.1区分大小写
JavaScripe是区分大小写的语言,HTML并不区分(尽管XHTML区分)。
2.1.2空格、换行符和格式控制符
JavaScript会忽略程序中标识(Token)之间的空格,多数情况下同样会忽略换行符。
通用类别值(Zs、Cf)
2.1.3Unicode转义序列
使用6个ASCII字符来代表任意16位Unicode内码,以“\u”为前缀,后跟4个十六进制数
2.1.4标准化
允许使用多种方法对同一个字符进行编码,比如e(带语调符);标准为所有字符定义了一个首选的编码格式,并给出了一个标准化的处理方式将文本转换为一种适合比较的标准格式
2.2注释
行尾// /**/
2.3直接量
12//数字
1.2//小数
"hello" 或'Hi'//字符串
true//布尔值
/javascript/gi //正则表达式(用做模式匹配)
null //空
{ x:1,y:2} //对象
[1,2,3,4,5] //数组
2.4标识符和保留字
标识符用来对变量和函数进行命名,或者用作代码中某些循环语句中的跳转位置的标记。以字母、_或&开始,数字不允许作为首字母。通常只用ASCII,允许出现Unicode(Mn类、Mc类和Pc类)。
保留字
......
保留了一些关键字,可能在未来版本中用到
也有在普通代码中合法,在严格模式下是保留字
严格模式下对 arguments eval 做了严格限制,他们并不完全是保留字,但不能用做变量名、函数名或参数名
ECMAScript将Java的所有关键字都列为自己的保留字,尽管在5中放宽了限制,为了对低版本的支持也要避免使用
Javascript预定义了很多全局变量和函数,应当避免把他们的名字用作变量名和函数名
*Javascript的具体事项可能定义独有的全局变量和函数,每一种特定的Javascript运行环境(客户端、服务器等)都有自己的一个全局属性列表
2.5可选的分号
合适地添加分号
*return、break、continue和随后的表达式之间不能有换行
第三章 类型、值和变量
能够表示并操作的值的类型称作数据类型(type)
Javascript的数据类型分为两类:1、原始类型(数字、字符串和布尔值) 2、对象类型(全局对象、数组和函数)。有两个特殊的原始值:null和undefined,它们通常分别代表了各自特殊类型的唯一的成员。
如果函数用来初始化(用new运算符)一个新建的对象,我们称之为构造函数,每个构造函数定义了一类(class)对象——由构造函数初始化的对象组成的集合。类可以看做是对象类型的子类型。(除数组Array和函数Function类外,还有日期Date类定义了代表日期的对象。正则RegExp类定义了表示正则表达式,错误Error类定义了表示程序中运行时错误和语法错误的情况)。
Javascript有自己的内存管理机制,自动对内存进行垃圾回收,程序可按需创建队形,程序员不必的内心这些对象的销毁和内存回收,当不咋有任何引用只想一个对象,解释器就会知道这个对象没用了,然后自动回收它所占用的内存资源。
*作为面向对象的语言(抽象、封装、继承、多态)。不严格地讲,意味着我们不用全局的定义函数去操作不同类型的值,数据类型本身可以定义方法(method)来使用值。例如,要对数组a中的元素进行排序,不必要将a传入sort()函数,而是调用a的一个方法sort():
a.sort();//sort(a)的面向对象的版本。
从技术上讲只有对象才能拥有方法。然而数字、字符串和布尔值也可以拥有自己的方法,在JavaScript中只有null和undefined是无法拥有方法的值。
类型可以分类为:1原始类型 对象类型
2可以拥有方法的类型 不能拥有方法的类型
3可变类型(对象和数组) 不可变类型(数字、布尔值、null和undefined)
可以自由地进行数据类型转换
变量是无类型的,可被赋予任何类型的值,同时也可以重新赋予不同类型的值,用var关键字声明变量
3.1数字
不区分整型值和浮点数值,所有均用浮点数值表示(IEEE 754 64位浮点格式-253~253)1符号 11阶码 52尾数
*注意实际的操作(比如数组索引及位操作符)则是基于32位整数
*数字直接出现在程序中,称之为数字直接量,在任何数字前添加负号(-)可以得到负值,但负号是一元求反运算符,并不是数字直接量语法的组成部分。
3.1.1整型直接量
十进制,十六进制(“0x”或“0X”为前缀),八进制直接量有些是不支持的,尽量不要使用
3.1.2浮点型直接量
eg:3.14 6.02e23 1.472E-32
3.1.3JavaScript中的算术运算
+、-、*、/、%
Math.pow(2,53) //2的53次幂
Math.round(.6) //1.0,四舍五入
Math.ceil(.6) //1.0,向上求整
Math.floor(.6) //0.0
Math.abs(-5) //5
Math.max(x,y,z)
Math.min(x,y,z)
Math.random() //生成大于0小于1.0的伪随机数
Math.PI //圆周率
Math.E //自然对数的底数
Math.sqrt(3) //3的平方根
Math.sqrt(3,1/3) //3的立方根
Math.sin(0) Math.cos(0) Math.atan
Math.log(10) //10的自然对数ln10
Math.log(100)/Math.LN10 //以10为底100的对数
Math,log(1024)/Math.LN2 //10
Math.exp(3) //e的三次幂
*更多看第三部分Math对象的介绍
算数运算在溢出、下溢或被零整除是不会报错。
超过数字上限(溢出)是结果为一个无穷大值 Infinity下限是-Infinity,基于它们的加、减、乘和除运算结果还是无穷大值;
下溢是当运算结果比Javascript能表示的最小值还小时发生的情形,会返回0,负值会返回“负零” ;
被零整除时只是返回无穷大或负无穷大。例外是零除以零是没有意义的,运算结果是一个非数字值(not-a-number)值,用NaN表示。无穷大除以无穷大,给任意负数开方或者算术运算符与不是数字或无法转换为数字的操作数一起使用时都将返回NaN.
Infinity和NaN在ECMAScript 5中被修正定义为只读,3中Number对象定义的属性值也是只读的
非数字值和任何值都不想等,包括自身,所以没办法通过x==NaN来判断变量x石佛是NaN。相反应当使用x!=x来判断,当且仅当x为NaN的时候,表达式的结果才为true,isNaN()的作用与此类似,如果参数是NaN或者是一个非数字值(如字符串和对象),则返回true。JavaScript中有一个类似的函数isFinite(),在参数不是NaN、Infinity或-Infinity的时候返回true。
负零值同样特殊,它和正零值是相等的,所以除了作为除数之外几乎一模一样。
3.1.4二进制浮点数和四舍五入错误
任何使用二进制浮点数的编程语言中都会有这个问题。因为速发精确表示类似0.1(十进制分数1/10、1/100等)这样简单的数字。有足够的精度,并可以极其近似于0.1。问题会在判断类似于0.3-0.1和0.2-0.1是否相等时才会出现,未来版本或许会支持十进制数字类型以避免。
3.1.5日期和时间
var then = new Date(2011,0,1) ;//2011年1月1日
var later = new Date(2011,0,1,17,10,30);
var now = new Date();
var elapsed = new - then; //计算相隔毫秒数
later.getFullYear();
later.getMonth() //从0开始计数的月份
later.getDate() //从1开始计数的天数
later.getDay() //星期数,星期天是0
later.getHours() //当地时间
later.getUTCHours() //使用UTC表示小时,基于时区
第三部分有更多细节
3.2文本
字符串是一组由16位值族称给的不可变的有序序列,每个字符通常来自于Unicode字符集。JavaScript通过字符串类型来表示文本。字符串的长度是含16位值的个数,从零开始。字符串操作方法均作用于16位值,而非字符。
*那些不能表示为16位的Unicode字符则遵循UTF-16编码规则——用两个16位值组成的一个序列(亦称作“代理项对”)表示,这意味着一个长度为2的javascript字符串有可能表示一个Unicode字符。
3.2.1字符串直接量
由单引号或双引号括起来的字符序列。单引号和双引号可以相互包含。3中字符串直接量必须卸载一行中,而在5中可拆分成数行,必须以反斜线(\)结束。
*注意用单引号定界字符串是,英文当中的缩写和所有格can‘t和O’Reilly‘s必须使用\来转义所有的’。
*当代码中夹杂HTML代码的字符串时,最好两种代码中各自使用独立的引号风格。
3.2.2转义字符
\o NUL字符 \b 退格符 \t 水平制表符 \n换行符 \v垂直制表符 \f 换页符 \r 回车符
\" \' \\ \xXX Latin-1字符 \uXXXX Unicode字符
3.2.3字符串的使用
“+”连接字符串 s.length:包含的16位值的个数,字符串s的长度
var s="hello,word"
s.charAt(0)
s.charAt(s.length-1)
s.substring(1,4) "ell" 2~4
s.slice(1,4) 同上
s.slicez(-3) "rld"最后3个
s.indexOf("l") 2:字符l首次出现的位置
s.lastIndexOf("l") 10:l最后出现的位置
s,indexOf("l",3) 3:在位置3及之后首次出现字符l的位置
s.split(",") ["hello","world"]分割成子串
s.replace("h","H") "Hello,world"
s.toUpperCase() "HELLO,WORLD"
*类似replace()和toUpperCase()的方法都返回新字符串,原字符串本身并没有发生改变。
也可用s[0] s[s.length-1]来访问单个字符
3.2.4模式匹配
RegExp和String对象均定义了利用正则表达式进行模式匹配和查找与替换的函数
RegExp并不是JavaScript的基本类型,和Date一样,它只是一种具有实用API的特殊对象。
虽不是语言中的基本数据类型,他们依然具有直接量写法,可以直接在js中使用g.zai两条斜线之间的文本构成里一个正则表达式直接量。
第二个斜向之后也可以跟随一个或多个字母,用来修饰匹配模式的含义
/^HTML/ //匹配以HTML开始的字符串
/[1-9][1-9]*/ //匹配一个非零数字,后面是人一个数字
/\bjavascript\b/i //匹配单词“javascript”,忽略大小写
RegExp对象定义了很多有用的方法,字符串同样具有可以接受RegExp参数的方法
var text="testing:1,2,3";
var pattern = /\d+/g 匹配所有包含一个或多个数字的实例
pattern.test(text) true:匹配成功
text.search(pattern) 9:首次匹配成功的位置
text.matchd(pattern) ["1","2","3"]:所有匹配成功的数组
text.replace(pattern,"#") "testing:#,#,#"
text.splite(/\D+/); ["","1","2","3"]用非数字字符截取字符串
3.3布尔值
true和false
1、比较语句的结果 a==4
2、控制结构 if/else
3、任意的值都可以转换为布尔值
undefined null 0 -0 NaN “ ”都会被转换成false(假值)
所有其他值,包括所有对象(数组)都会转换成true(真值)
4、toString()方法可以将字符串转换为“true”或“false”
5、&& || NOT
3.4null和undefined
1、null是关键字,表示一个特殊值,常用来描述“空值”
对null进行typeof预算,结果会分会“object”,可以将null认为是一个特殊的对象值,含义是“非对象”
它可以表示数字、字符串和对象是“无值”的。
2、undefined也可以表示值的空缺。表示更深层次的“空值”。他是变量的一种取值,表示变量没有初始化,要查询对象属性或数组元素时返回undefined则说明这个属性或元素不存在。函数没有返回任何值时则返回它。引用没有提供实参的函数形参的值也只会得到undefined。
是预定义的全局变量,不是关键字,值就是未定义。在5中被修正为只读的。
typeof会返回“undefined”
3、虽然不同 ,但它们都表示值得空缺,两者可以互换。“==”认为两者是相等的,要用“===”严格地来区分它们。都不包含任何属性和方法,用“.”和“[]”来存取这两个值得成员或方法都会产生一个类型错误。
4、undefined 系统级的、出乎意料的货类似错误的值的空缺
null 程序级的、正常的或在意料之中的值的空缺
如果想将他们赋值给变量或者属性,或者将他们作为参数传入函数,最佳选择是使用null
3.5全局对象
重要用途:全局对象的属性是全局定义的符号,程序可以直接使用。
当解释器启动时(或任何Web浏览器加载新页面的时候),它将创建一个新的全局对象,并给它一组定义的初始属性:
全局属性,比如undefined、Infinity、和NaN
全局函数,比如isNaN()、parseInt()和eval()
构造函数,比Date()、RegExp()、String()、Object()和Array()
全局对象,比如Math和JSON
*他们并不是保留字,但应当做保留字来对待。可以通过名称查找到,或者通过别名“Global”来找到这些全局对象。对于客户端Javascript,Window对象定义了以为额外的全局属性。
在代码最顶端——不在任何函数内的Javascript代码,可以用this来引用全局变量
eg:var global = this;
在客户端javascript中,Window对象充当了全局对象。这个全局对象有一个属性window引用其自身,它可以代替this来引用全局对象。
初次创建时,全局队形定义了Javascript中所有的预定义全局值
3.6包装对象
字符串 String() 数字 Number() 布尔值 Boolean()
构造函数会为其前的值构建一个临时对象,这些方法的调用均是来自于这个临时对象。
*null、undefined没有包装对象
eg : var s="test";
s.len=4;
var t=s.len;
运行后t的值是undefined。第二行代码创建一个临时字符串对象,并给其len属性赋值为4,随即销毁这个对象。第三行通过原始的字符串值创建一个新字符串对象,尝试读取其len属性,这个属性自然不存在。
*说明在读取时表现的像对象一样,但如果试图给属性赋值,则会忽略这个操作,修改只发生在临时对象身上,而这个临时对象并未保留下来。
属性都是制度的,并且不能给他们定义新属性,因此它们有别于对象。
也可用以上构造函数来显示创建包装对象 var s=“test”;
var S=new String(s)
javascript会在必要时将包装对象转换成原始值,因此以上的S对象常常但不总表现地和s一样,“==”时是为相等,“===”时不等
3.7不可变的原始值和可变的对象引用
原始值(undefined、null、布尔值、数字和字符串)与对象(包括数组和函数)有着根本区别。
1、原始值不可更改。对于字符串看起来不那么明显,因为看起来像有字符组成的数组,我们期望可以通过制定索引来修改,但实际上是禁止的。
*字符串的所有的方法看上去返回了一个修改后的字符串,实际上返回的是一个新的字符串值
var s="hello";
s.toUpperCase(); //返回“HELLO”但并没改变s
s //“hello”
原始值的比较与对象的比较不同
2、对象的值是可修改的,但对象的比较并非值得比较,及时两个对象包含同样的属性及相同的值,他们也是不想等的。数组也是。
对象成为引用对象,只有引用同一个基对象时他们才相等。同时将对象(或数组)赋值给一个变量,仅是赋值的引用量,对象本身并没有复制一次。如果想得到副本,必须显式复制对象的每一个属性或数组的每一个元素。
3.8类型转换
类型转换表 P49
3.8.1转换和相等性
“==”会做类型转换 “===”未做类型转换
if语句将undefined转换为false,但“==”运算符从不试图将其操作数转换为布尔值
3.8.2显式类型转换
Number(); String() Boolean() Object()当不带new运算符调用时,他们会作为转换函数做类型转换
+ 字符串 x+“” +数字 +x !布尔值 !!x注意是双叹号
Number类定义的toString()方法可以接受表示转换基数的可选参数(2,8,16),默认时是十进制
toFixed()方法,根据小数点后的指定尾数将数字转换为字符串,不适用指数计数法
toExponential()使用指数计数法将数字转换为指数形式的字符串,其中小数点前只有一位,小数点年后的尾数有参数指定
toPrecision()根据制定的额有效数字为数将数字转换成字符串,如果有效数字的尾数少于数字证书部分的位数,则转换成指数形式。
Number()转换函数传入字符串时,它会驶入将其转换为一个整数或浮点数直接量,这个方法只能基于十进制数进行转换,并且不能出现非法的尾随字符。
parseInt()函数和parseFloat()函数他们是全局函数,不从属于任何类的方法,更加灵活。其中parseInt()转换的字符串是“0x”或“0X”时,将会解释为十进制数。二者都会跳过任意数量的前导空格,尽可能解析更多数值字符,并忽略其后内容。parseInt()可接受第二个可选参数,这个餐宿制定数字转换的基数,取值为2~36(P52)
3.8.3对象转换为原始值
1、转换为布尔值时全是true
2、对象到字符串和对象到数字的转换需要调用带转换对象的一个方法来完成。有两个不同的方法。
a、 一个是toString()方法,它的作用是返回一个反映这个对象的字符串。默认的方法不会反应一个有趣的值。
很多类定义了更多特定版本的toSting()方法。
例如:数组类(Array)的方法将每个元素转换为一个字符串,在元素之间添加逗号后合并成一个结果字符串。
函数类(Function)返回这个函数的实现定义的表示方式,通常是将用户定义的函数准还为源代码字符串。
日期类(Date)返回了一个可读的日期和时间字符串
RegExp类返回正则表达式
b、另一个是valueOf():如果存在任意原始值,它就默认将对象转换为表示它的原始值。对象是复合值,而且大多数对象无法真正表示为一个原始值,因此默认的方法简单的返回对象本身而不是一个原始值。
数组、函数和正则表达式简单地继承了这个默认方法,调用这些类型的实例的该方法知识简单返回对象本身。日期类定义的valueOf()返回它的一个内部表示:1970年1月1日以来的毫秒数
3、在某些特殊场景下,javascript执行了完全不同的对象到原始值的转化。
4、对象到字符串的转换
a、先调用toString()方法,如果返回原始值则转换为字符串
b、如果没有toString()或返回的并不是一个原始值,那么会调用valueOf()方法。如果返回值是原始值将其转换为字符串,并返回这个字符串结果。
c、否则抛出一个类型错误异常
对象到数字的转换
a、先调用valueOf()方法
b、否则调用toString()方法
c、类型错误异常
P54
*日期类是语言核心中唯一的预先定义类型
3.9变量声明
var 可声明多个变量,还可以将变量的初始赋值和变量声明合写在一起。
*如果未在var声明语句中给变量制定初始值,即使生明了变量,它的初始值仍是undefined。
在循环体for和for/in循环中同样可以使用var语句,更简洁地声明在循环体语法中使用的循环变量
编程语言分为动态(类型)语言和静态(类型语言),动态类型语言是指在运行期间才去做数据类型检查的语言,即永远也不用给任何变量制定数据类型,该语言会在第一次赋值给变量是,在内部将数据类型记录下来。Python,Ruby和JavaScript就是典型的动态类型语言。静态类型语言与动态语言刚好相反,它的数据类型是在编译期间检查的,也就是说在写程序是要声明所有变量的数据类型,C/C++是静态类型语言的典型代表,其他的静态类型语言还有C#,JAVA等。
重复的声明无害,二遗漏的生命应该避免,尽管非严格模式下回给全局对象创建一个同名属性,并且工作起来向一个正确声明的全局变量,但会造成bug
3.10变量作用域
作用域是程序源代码中定义这个变量的区域
全局变量,局部变量(函数内声明,函数参数)
函数体内,局部变量的优先级高于同名的全局变量。
全局作用域编写代码时可以不写var语句,二声明局部变量时不许使用var语句。
由于函数可以嵌套,所以会出现几个局部作用域嵌套的情况。
3.10.1函数作用域和声明提前
在类似C语言的编程语言中,花括号内的梅一段代码都具有各自的作用域,而且变量在声明它们的代码段之外是不可见的,我们成为块级作用域。而JavaScript中没有块级作用域,取而代之的使用了函数作用域:变量在声明他们的函数体以及这个函数体嵌套的任意函数体内都是有定义的。
这意味着变量在声明之前甚至已经可用,这个独特性被非正式地成为声明提前(hoisting),即函数里声明的所有变量(不涉及赋值)都被“提前”至函数体的顶部。P58所以将变量声明放在函数体顶部,而不是将声明靠近放在使用变量指出。可以是源代码非常清晰的反映了真实的变量作用域
3.10.2作为属性的变量
当声明一个全局变量时,实际上是定义了全局对象的一个属性。当时用var声明一个变量是,创建的这个属性是不可配置的,也就四说这个变量无法通过delete运算符删除。如果没有使用严格模式并给一个未声明的变量赋值的话,JavaScript会自动创建一个全局变量。以这种方式创建的变量是全局对象的正常的可配置属性,并可以删除它们。
全局变量是全局对象的属性,对于局部变量没有如此规定,但我们可以想象得到,局部变量当作跟函数调用相关的某个对象的属性。3称该对象为调用对象(call object),5称为声明上下文对象(declarative enviroment record)。js可以允许使用this关键字来引用全局对象,却没有方法可以引用局部变量中存放的对象,这是一种不可见的内部实现。然而,这些局部变量对象存在的观念是非常重要的
3.10.3作用域链 P59
js是基于语法作用域的语言:通过阅读包含变量定义在内的数行源码就能知道变量的作用域。