本章内容:

任何语言的核心都必然会描述这门语言最基本的工作原理。而描述的内容通常都要涉及这门语言的语法,操作符,数据类型,内置功能等用于构建复杂方案的基本概念。

##3.1 语法

###3.1.1 区分大小写

要理解的第一个概念就是ECMAScript中的一切(变量,函数名和操作符)都区分大小写。

###3.1.2 标识符

所谓标识符,就是指变量,函数,属性的名字,或者函数的参数。

按照惯例,ECMAScript标识符采用驼峰大小写格式

###3.1.3 注释

单行注释和多行注释

###3.1.4 严格模式

严格模式是为JavaScript定义了一种不同的解析与执行模型。

要在整个脚本中启用严格模式,可以在顶部添加如下代码: "use strict";

###3.1.5 语句

代码行结尾处没有分号会导致压缩错误。另外,加上分号也会在某些情况下增进代码的性能,因为这样解析器就不必再花时间推测应该再哪里插入分号了

但最终实践是始终在控制语句中使用代码块

##3.2 关键字和保留字

ECMA-262描述了一组具有特定用途的关键字,还描述了另外一组不能用作标识符的保留字,它们有可能在将来被用作关键字

##3.3 变量

ECMAScript的变量时松散类型的,所谓松散类型就是可以用来保存任何类型的数据。

像这样var message;未经过初始化的变量,会保存一个特殊的值——undefined

初始化变量并不会把它标记为字符串类型;初始化的过程就是给变量赋一个值那么简单。因此,可以在修改变量值的同时修改值的类型,如下所示

	var message = "hi";
	message = 100;//有效,但不推荐

有一点必须注意,即用var 操作符定义的变量将成为定义该变量的作用域中的局部变量。也就是说,如果在函数中使用var定义一个变量,那么这个变量在函数退出后就会被销毁,例如:

	function test(){
		var message = "hi";//局部变量
	}
	test();
	alert(message);//错误!

不过,可以像下面这样省略var操作符,从而创建一个全局变量:

	function test(){
		message = "hi";//全局变量
	}
	test();
	alert(message);//"hi";

messag成为了全局变量,这样,只要调用过一次test()函数,这个变量就有了定义,就可以在函数外部的任何地方被访问到。

但这也不是我们推荐的做法。以为在局部作用域中定义的全局变量很难维护。

如果使用语句定义多个变量,可以把每个变量用逗号分隔开

##3.4 数据类型

ECMAScript中有5种简单数据类型(也称为基本数据类型):Undefined,Null,Boolean,Number和String。还有一种复杂数据类型——objec,object本质上是由一组无序的名值对组成的。所有值最终都将是上述6种数据类型之一。

由于ECMAScript数据类型具有动态性,因此的确没有再定义其他数据类型的必要了。

###3.4.1 typeof操作符

检测给定变量的数据类型。注意,typeof是一个操作符而不是函数,因此例子中的圆括号尽管可以使用,但不是必需的。

有些时候,typeof操作符会返回一些令人迷惑但技术上却正确的值。比如,调用typeof null会返回”object”,因为特殊值null被认为是一个空的对象引用。

通过typeof操作符来区分函数和其他对象是有必要的。

###3.4.2 Undefined类型

对于尚未声明过的变量,只能执行一项操作,即使用typeof操作符检测其数据类型(对未经声明的变量调用delete不会导致错误,但这样做没什么实际意义,而且在严格模式下确实会导致错误)

对未初始化和未声明的变量执行typeof操作符都返回了undefined值,实际上无论对哪种变量也不可能执行真正的操作。

显式地初始化变量依然是明智的选择。当typeof操作符返回”undefined”值时,我们就知道被检测的变量还没有被声明,而不是尚未初始化。

###3.4.4 Null类型

Null类型是第二个只有一个值的数据类型,这个特殊的值是null。从逻辑角度来看,null值表示一个空对象指针,而这也正是使用typeof操作符检测null值时会返回”object”的原因。

如果定义的变量准备在将来用于保存对象,那么最好将该变量初始化为null而不是其他值。这样一来,只要直接检查null值就可以知道相应的变量是否已经保存了一个对象的引用,如下面的例子所示:

	if(car !=null){
		//对car对象执行某些操作
	}

实际上,undefined值是派生自null值的,因此ECMA-262规定对它们的相等性测试要返回true:

	alert(null == undefined);//true

不过要注意的是,这个操作符出于比较的目的会转换其操作数。

只要意在保存对象的变量还没有真正保存对象,就应该明确地让该变量保存null值。

###3.4.4 Boolean类型

Boolean类型是ECMAScript中使用得最多得一种类型,该类型只有两个字面值:true和false。这两个值与数字值不是一回事,因此true不一定等于1,而false也不一定等于0

需要注意的是,Boolean类型的字面值true和false是区分大小写的。也就是说,True和False以及其它的混合大小都不是Boolean值,只是标识符。

要将一个值转换为其对应的Boolean值,可以调用转型函数Boolean()。

可以对任何数据类型的值调用Boolean函数。这些转换规则对理解流控制语句(如if语句)自动执行相应的Boolean转换非常重要

###3.4.5 Number类型

Number类型应该是ECMAScript中最令人关注的数据类型了。

整数还可以通过八进制或十六进制的字面值来表示。其中,八进制字面值的第一位必须是零(0),然后是八进制数字序列(0~7)。如果字面值汇总的数值超出了范围,那么前导零将被忽略,后面的数值将被当做十进制数值解析。

十六进制字面值的前两位必须是0x,后跟任何十六进制数字。

1.浮点数值

	var floatNum3 = .1;//有效,但不推荐

由于保存浮点数值需要的内存空间是保存整数值的两倍,因此ECMAScript会不失时机地将浮点数值转换为整数值。

默认情况下,ECMAScript会将那些小数点后面带有6个零以上的浮点数值转换为以e表示法表示的数值

浮点数值的最高精度是17位小数,但在进行算术计算时其精确度远远不如整数。例如0.1加0.2的结果不是0.3。这个小小的舍入误差会导致无法测试特定的浮点数值。

永远不要测试某个特定的浮点数值

关于浮点数值计算会产生舍入误差的问题,有一点需要明确:这是使用基于IEEE754数值的浮点计算的通病,ECMAScript并非独此一家;其他使用相同数值格式的语言也存在这个问题。

2.数值范围

由于内存的限制,ECMAScript并不能保存世界上所有的数值。

如果某次计算反悔了正或负的Infinity值,那么该值将无法继续参与下一次的计算,因为Infinity不是能够参与计算的数值。

要想确定一个数值是不是有穷的,可以使用isFinite()函数。

3.NaN

NaN,即非数值(Not a Number)是一个特殊的数值,这个数值用于表示一个本来要返回数值的操作数未返回数值的情况(这样就不会抛出错误了)。

0除以0才会返回NaN,整数除以0返回Infinity,负数除以0返回-Infinity。

尽管有点不可思议,但isNaN()确实也适用于对象。

4.数值转换

有3个函数可以把非数值转换为数值:Number(),parseInt()和parseFloat()。第一个函数,即转型函数Number()可以用于任何数据类型,而另两个函数则专门用于把字符串转换成数值。这三个函数对于同样的输入会有返回不同的结果。

一元加操作符的操作与Number()函数相同。

由于Number()函数在转换字符串时比较复杂而且不够合理,因此在处理整数的时候更常使用的是parseInt()函数。parseInt()函数在转换字符串时,更多的是看其是否符合数值模式。它会忽略字符串前面的空格,直至找到第一个非空格字符。

在ECMAScript 3 JavaScript引擎中,”070”被当成八进制字面量,因此转换后的值是十进制的56.而在ECMAScript 5 JavaScript引擎中,parseInt()已经不具有解析八进制值的能力,因此前导的零会被认为无效,从而将这个值当成”70”,结果就得到十进制的70。在ES5中,即使是在非严格模式下也会如此。

为了消除在使用parseInt()函数时可能导致的上述困惑,可以为这个函数提供第二个参数:转换时使用的基数(即多少进制)。

不指定基数意味着让parseInt()决定如何解析输入的字符串,因此为了避免错误的解析,我们建议无论在什么情况下都明确指定基数。

除了第一个小数点有效之外,parseFloat()与parseInt()的第二个区别在于它始终都会忽略前导的零。

由于parseFloat()只解析十进制值,因此它没有用第二个参数指定基数的用法。

最后还要注意一点:如果字符串包含的是一个可解析为整数的数(没有小数点,或者小数点后都是零),parseFloat()会返回整数。