首页 > 代码库 > JS基础知识回顾:ECMAScript的语法(三)

JS基础知识回顾:ECMAScript的语法(三)

ECMA-262描述了一组用于操作数据值的操作符,包括算术操作符、位操作符、关系操作符和相等操作符。

ECMAScript操作符的与众不同之处在于,他们能够适用于很多值,例如字符串、数字值、布尔值、甚至是对象。

在将这些操作符应用于对象时,相应的操作符通常都会调用对象的valueOf()和(或)toString()方法,以便取得可以操作的值。

 

只能操作一个值的操作符叫做一元操作符。

递增和递减操作符直接借鉴自C,各有前置型和后置型两个版本:a++、++a、a--、--a

这四种操作符不仅适用于整数,还可以用于字符串、布尔值、浮点数值和对象。

在应用于不同数值时,递增和递减操作符遵循下列规则:

在应用于一个包含有效数字字符的字符串时,先将其转换为数字值,在执行加减1的操作,字符串变量变成数值变量;

在应用于一个不包含有效数字字符的字符串时,将变量的值设置为NaN,字符串变量变成数值变量;

在应用于布尔值false时,先将其转换为0再执行加减1的操作,布尔值变量变成数值变量;

在应用于布尔值true时,先将其转换为1再执行加减1的操作,布尔值变量变成数值变量;

在应用于浮点数值是,执行加减1的操作;

在应用于对象时,先调用对象的valueOf()方法以取得一个可供操作的值,然后对该值按照上述规则进行操作,如果结果是NaN,则再调用toString()方法后再应用上述规则,对象变量变成数值变量。

一元加操作符以一个加号(+)表示。

一元加操作符放在数值前面,对数值不会产生任何影响;在对非数值应用一元操作符时,该操作符会向Number()函数一样对这个值执行转换。

一元减操作符主要用于表示负数,用一个减号(-)表示。

一元减操作符应用于数值时,该值会变成负数;而在应用于非数值时,一元减操作符遵循与一元加操作符相同的规则,最后将得到的数值转换为负数。

一元加减操作符主要用于基本的算术运算,也可以像前面所展示的一样用于转换数据类型。

 

位操作符用于在最基本的层次上,即按内存中表示数值的位来操作数值。

ECMAScript中所有的数值都以IEEE-754 64位格式存储,但位操作符会先将64为的值转换成32位的整数,然后执行操作,最后再将结果转换为64位,不过对于开发人员来讲这个过程是透明的,因此整个过程就像是只存在32位的整数一样。

对于有符号的整数,32位中的前31位用于表示整数的值,第32位用于表示数值的符号:0表示正数,1表示负数。

这个表示符号的位叫做符号位,符号位的值决定了其他位数值的格式。

其中,正数以纯二进制格式存储,31位中的每一位都表示2的幂,第一位(叫做位0)表示2的0次幂,第二位表示2的1次幂,以此类推,没有用到的位以0填充。

另外,负数以二进制补码的形式存储:首先求这个数值绝对值的二进制码,然后再求该二进制码的反码(将0替换为1,将1替换为0),得到的二进制反码加1。

ECMAScript会尽力向我们隐藏所有这些信息,在以二进制形式输出一个负数时,我们看到的只是这个负数绝对值的二进制码前面加上了一个负号。

在处理有符号整数时,是不能访问位31(即第三十二位)的,默认情况下,ECMAScript中的所有整数都是有符号整数。

当然也存在无符号整数,对于无符号整数来讲第32位不再表示符号,因为无符号整数只能是正数,无符号整数因为多出一位来所以可以表示更大的数值。

在对特殊的NaN和Infinity值应用位操作时,这两个值都会被当成0来处理。

如果对非数值应用位操作符,会先使用Number()函数将该值转换为一个数值(自动完成),然后再应用位操作符,得到的结果是一个数值。

 

按位非操作符由一个波浪线(~)表示,执行按位非的结果就是返回数值的反码。

尽管按位非操作的本质是操作数的负值减1,但是由于是底层操作,会比直接运算速度更快。

按位与操作符由一个和号字符(&)表示,它有两个操作数。

从本质上讲,按位与操作就是将两个数值的每一位对齐,然后针对每一位做与操作。

按位与操作只有在两个数值的对应位都是1的情况下才返回1,任何一位是0结果都是0。

按位或操作符由一个竖线符号(|)表示,它有两个操作数。

从本质上讲,按位或操作就是将两个数值的每一位对齐,然后针对每一位做或操作。

按位或操作只有在两个数值的对应位都是0的情况下才返回0,任何一位是1结果都是1。

按位异或操作符由一个插入符号(^),它有两个操作数。

从本质上将,按位异或操作就是讲两个数值的每一位对齐,然后针对每一位做异或操作。

按位异或操作只有在两个数值的对应位中有一个是1时返回1,如果两个数值的对应为均为0或1时则返回0。

 

左移操作符由两个小于号(<<)表示,这个操作符会将所有数值的所有位向左移动指定的位数:oldValue<<5(向左移五位)

向左移位后,原数值的右侧多出的空位将用0填充,以便得到的结果是一个完整的32位二进制数。

左移不会影响操作数的符号位,换句话说,如果将-2向左移动5位,得到的结果将是-64。

有符号右移操作符由两个大于号(>>)表示,这个操作符会将数值向右移动,但保留符号位,在右移过程中产生的空位将用符号位来填充。

无符号右移操作符由三个大于号(>>>)表示,这个操作符会将数值的所有32位全都向右移动。

由于无符号右移操作符会将所有二进制数全部看做是正数来处理,并将移动后的空位用0填充。

所以对于正数来讲,无符号右移的结果与有符号右移相同,但对于负数来讲将产生很大的差别。

 

布尔操作符一共有三个:非(NOT)、与(AND)、或(OR)。

 

逻辑非操作符由一个叹号(!)表示,可以应用于ECMAScript中的任何值。

逻辑非操作符会将它的操作数(无论这个值是什么数据类型)首先转换为一个布尔值,然后再对其求反后返回一个布尔值:

如果操作数是一个对象,则返回false;

如果操作数是一个空字符串,则返回true;

如果操作数是一个非空字符串,则返回false;

如果操作数是数值0,则返回true;

如果操作数是任意非0数值(包括Infinity),则返回false;

如果操作数是null,则返回true;

如果操作数是NaN,则返回true;

如果操作数是undefined,则返回true。

如果同时用两个逻辑非操作符则会模拟Boolean()转型函数的行为,将操作数转换为其对应的布尔值。

 

逻辑与操作符由两个和号(&&)表示,有两个操作数,只有在两个操作数的值都是true时才返回true,否则返回false。

逻辑与操作可以应用于任何类型的操作数,而不仅仅是布尔值,在操作数不全是布尔值的情况下该操作也不一定返回布尔值:

如果第一个操作数是对象,则返回第二个操作数;

如果第二个操作数是对象,则只有在第一个操作数的求值结果为true的情况下才会返回该对象;

如果两个操作数都是对象,则返回第二个操作数;

如果有一个操作数是null,则返回null;

如果有一个操作数是NaN,则返回NaN;

如果有一个操作数是undefined,则返回undefined。

逻辑与操作属于短路操作,如果第一个操作数能够决定结果,那么就不会再对第二个操作数求值。

在逻辑与操作中使用未定义的值会导致错误,但如果是在第一个操作数的值为false第二个操作数未定义的情况下,由于不会对第二个操作数求值,所以并不会报错。

 

逻辑或操作符由两个竖线(||)表示,有两个操作数,只有在两个操作数的值都是false时才返回false,否则返回true。

逻辑或操作可以应用于任何类型的操作数,而不仅仅是布尔值,在操作数不全是布尔值的情况下该操作也不一定返回布尔值:

如果第一个操作数是对象,则返回第一个操作数;

如果第一个操作数的求值结果为false,则返回第二个操作数;

如果两个操作数都是对象,则返回第一个操作数;

如果两个操作数都是null,则返回null;

如果两个操作数都是NaN,则返回NaN;

如果两个操作数都是undefined,则返回undefined。

与逻辑与操作类似,逻辑或操作也属于短路操作,如果第一个操作数的结果为true,那么就不会再对第二个操作数求值。

我们可以利用逻辑或的这一行为来避免为变量赋null或undefined值,例如:var myObject=preferredObject||backupObject;

此例子中如果preferredObject的值不是null,那么它将被赋给myObject,如果是null,则将backupObject赋值给myObject,ECMAScript程序的赋值语句经常会使用这种模式。

 

ECMAScript定义了三个乘性操作符:乘法、除法和求模。

如果参与乘性计算的某个操作数不是数值,后台会先使用Number()转型函数将其转换为数值。

 

乘法操作符由一个星号(*)表示,用于计算两个数值的乘积。

在处理特殊值的情况下,乘法操作符遵循下列特殊规则:

如果操作数都是数值,执行常规的乘法计算,如果乘积超过了ECMAScript数值的表示范围,则返回Infinity或-Infinity;

如果只有一个操作数是NaN,则结果是NaN;

如果是Infinity与0相乘,则结果是NaN;

如果是Infinity与非0数值相乘,则结果是Infinity或-Infinity;

如果有一个操作数不是数值,则在后台调用Number()将其转换为数值然后再应用上述规则。

 

除法操作符由一个斜线符号(/)表示,执行第二个操作数除第一个操作数的计算。

除法操作符对于特殊的值也有特殊的处理规则:

如果操作数都是数值,执行常规的除法计算,如果商超过了ECMAScript的数值范围,则返回Infinity或-Infinity;

如果有一个操作数是NaN,则结果是NaN;

如果是Infinity被Infinity除,则结果是NaN;

如果是零被零除,则结果是NaN;

如果是非零的有限数被零除,则结果是Infinity或-Infinity;

如果是Infinity被任何非零数值除,则结果是Infinity或-Infinity;

如果有一个操作数不是数值,则在后台调用Number()将其转换为数值然后再应用上述规则。

 

求模(余数)操作符由一个百分号(%)表示。

与另外两个乘性操作符类似,求模操作符会遵循下列特殊规则:

如果操作数都是数值,执行常规的除法计算,返回除得的余数;

如果被除数是无穷大值而除数是有限大的数值,则结果是NaN;

如果被除数是有限大的数值而除数是零,则结果是NaN;

如果是Infinity被Infinity除,则结果是NaN;

如果被除数是有限大的数值而除数是无穷大的数值,则结果是被除数;

如果被除数是零,则结果是零;

如果有一个操作数不是数值,则在后台调用Number()将其转换为数值然后再应用上述规则。

 

在ECMAScript中,加法和减法两个加性操作符都有一系列特殊行为。

 

加法操作符(+)在两个操作符都是数值时执行常规的加法计算,然后根据下列规则返回结果:

如果有一个操作数是NaN,则结果是NaN;

如果是Infinity加Infinity,则结果是Infinity;

如果是-Infinity加-Infinity,则结果是-Infinity;

如果是Infinity加-Infinity,则结果是NaN;

如果是+0加+0,则结果是+0;

如果是-0加-0,则结果是-0;

如果是+0加-0,则结果是+0。

不过如果有一个操作数是字符串,就要遵循如下规则:

如果两个操作数都是字符串,则将第二个操作数与第一个操作数拼接起来;

如果只有一个操作数是字符串,则将另一个操作数转换为字符串,然后再将两个字符串拼接起来。

忽略加法操作符的数据类型是ECMAScript变成中最常见的一个错误,如果想先对数值进行求解再与字符串拼接的话记得要加括号。

 

减法操作符(-)在处理各种数据类型转换时,同样需要遵循一些特殊规则:

如果两个操作符都是数值,则执行常规的算术减法操作并返回结果;

如果有一个操作数是NaN,则结果是NaN;

如果是Infinity减Infinity,则结果是NaN;

如果是-Infinity减-Infinity,则结果是NaN;

如果是Infinity减-Infinity,则结果是Infinity;

如果是-Infinity减Infinity,则结果是-Infinity;

如果是+0减+0,则结果是+0;

如果是+0减-0,则结果是-0;

如果是-0减-0,则结果是+0;

如果有一个操作数是字符串、布尔值、null或undefined,则现在后台调用Number()函数将其转换为数值,然后再根据前面的规则执行减法计算;

如果有一个操作数是对象,则调用对象的valueOf()方法以取得表示该对象的数值,如果对象没有valueOf()方法,则调用其toString()方法并将得到的字符串转换为数值。

 

小于(<)、大于(>)、小于等于(<=)、大于等于(>=)这几个关系操作符用于对两个值进行比较,这几个操作符都返回一个布尔值。

与ECMAScript中的其他操作符一样,当关系操作符的操作数使用了非数值时,也要进行数据转换:

如果两个操作数都是数值,则执行数值比较;

如果两个操作数都是字符串,则比较两个字符串对应的字符编码值(会按位比较字符编码,所有的大写字母编码小于小写字母,两数字字符串比较时也会按位比较);

如果一个操作数是数值,则将另一个操作数转换为一个数值,然后执行数值比较;

如果一个操作数是对象,则调用这个对象的valueOf()方法,用得到的结果按照前面的规则执行比较,如果没有该方法就调用toString()方法并对返回的结果做比较;

如果一个操作数是布尔值,则先将其转换为数值,然后再执行比较。

按照常理,如果一个值不小于另一个值,则一定大于或等于那个值,但是NaN与任何操作数执行任何比较时都会返回false。

 

ECMAScript中提供了两组相等操作符:相等和不相等——先转换再比较,全等和不全等——仅比较而不转换。

ECMAScript中的相等操作符为(==),不相等操作符为(!=)。

这两个操作符都会先转换操作数,然后再比较他们的相等性,有如下规则:

如果有一个操作数是布尔值,则在比较相等性之前先将其转换为数值,false转换为0,true转换为1;

如果一个操作数是字符串,另一个操作数是数值,在比较相等性之前先将字符串转换为数值;

如果一个操作数是对象,另一个操作数不是,则调用对象的valueOf()方法,用得到的基本类型值按照前面的规则进行比较;

在比较相等性之前,不能将null和undefined转换成其他任何值;

如果两个操作数都是对象,则比较它们是不是指向同一个对象。

下标列出了一些特殊情况及比较结果:

null==undefined//true;undefined==0//false;null==0//false

"NaN"==NaN//false;5==NaN//false;NaN==NaN//false;NaN!=NaN//true

false==0//true;true==1//true;true==2//false;"5"==5//true

ECMAScript中的全等操作符为(===),不全等操作符为(!==)。

全等比较在两个操作数未经转换就相等的情况下返回true,否则返回false。

注意:null==undefined会返回true,是因为他们是类似的值;而null===undefined会返回false,是因为他们是不同类型的值。

由于相等和不相等存在数据类型转换的问题,为了保持代码中数据类型的完整性更加推荐使用的是全等和不全等。

 

条件操作符variable=boolean_expression?true_value:false_value;

该操作的含义就是基于boolean_expression求值的结果,如果为true则给变量variable赋值true_value,如果为false则给变量variable赋值false_value。

 

简单的赋值操作符由等号(=)表示,其作用就是把右侧的值赋给左侧的变量。

如果等号前面再添加乘性操作符、加性操作符、位操作符,就可以完成复合赋值操作。

设计这些操作符的主要目的就是简化赋值操作,使用它们不会带来任何性能上的提升。

 

使用逗号操作符可以在一条语句中执行多个操作,例如:var num1=1,num2=2,num3=3;

逗号操作符还可以用来赋值,利用逗号操作符赋值总会返回表达式中的最后一项,例如:var num=(5,1,4,8,0);//num的值为0