高程三第三章之操作符
1.位操作符
在 ECMAScript 中,当对数值应用位操作符时,后台会发生如下转换过程:64 位的数值被转换成 32位数值,然后执行位操作,最后再将 32 位的结果转换回 64 位数值。这样,表面上看起来就好像是在操作 32 位数值,就跟在其他语言中以类似方式执行二进制操作一样。但这个转换过程也导致了一个严重的副效应,即在对特殊的 NaN 和 Infinity 值应用位操作时,这两个值都会被当成 0 来处理。
在有符号位二进制中,0为正值,1为负值。
位操作符是以二进制进行操作的,有如下几种:
1.按位非(NOT):按位非操作符由一个波浪线(~)表示,执行按位非的结果就是返回数值的反码。例如:
var num1 = 25; // 二进制为00000000000000000000000000011001
var num2 = ~num1; //二进制为11111111111111111111111111100110
alert(num2); // -26
这里,对 25 执行按位非操作,结果得到了-26。这也验证了按位非操作的本质:操作数的负值减 1。
2.按位与( AND):按位与操作符由一个和号字符(&)表示,它有两个操作符数。从本质上讲,按位与操作就是将两个数值的每一位对齐,都为时才为1,否则为0。
3.按位或(OR):按位或操作符由一个竖线符号(|)表示,同样也有两个操作数。二进制数的每一位对齐,全0为0,有1为1.
4.按位异或(XOR):操作符为(^),相同为0,相异为1.
5.左移:左移操作符由两个小于号(<<)表示,这个操作符会将数值的所有位向左移动指定的位数。例如,如果将数值 2(二进制码为 10)向左移动 5 位,结果就是 64(二进制码为 1000000),代码如下所示(左移不会影响操作数的符号位):
var oldValue = 2; // 等于二进制的 10
var newValue = oldValue << 5; // 等于二进制的 1000000,十进制的 64
6.有符号右移:有符号的右移操作符由两个大于号(>>)表示,这个操作符会将数值向右移动,但保留符号位(即正负号标记),正数用0填充,负数用1填充。有符号的右移操作与左移操作恰好相反,即如果将 64 向右移动 5 位,结果将变回 2:
var oldValue = 64; // 等于二进制的 1000000
var newValue = oldValue >> 5; // 等于二进制的 10 ,即十进制的 2
7.无符号右移:无符号右移操作符由 3 个大于号(>>>)表示,这个操作符会将数值的所有 32 位都向右移动。对正数来说,无符号右移的结果与有符号右移相同。但是对负数来说,情况就不一样了。首先,无符号右移是以 0 来填充空位,而不是像有符号右移那样以符号位的值来填充空位。其次,无符号右移操作符会把负数的二进制码当成正数的二进制码。而且,由于负数以其绝对值的二进制补码形式表示,因此就会导致无符号右移后的结果非常之大,如下面的例子所示:
var oldValue = -64; // 等于二进制的 11111111111111111111111111000000
var newValue = oldValue >>> 5; // 等于十进制的 134217726,二进制为000001111111111111111111111111110
2.布尔操作符
布尔操作符一共有 3 个:非(NOT)、与(AND)和或(OR)。
1.逻辑非:逻辑非操作符由一个叹号(!)表示,可以应用于 ECMAScript 中的任何值。无论这个值是什么数据类型,这个操作符都会返回一个布尔值。
如果操作数是 null,返回 true;
如果操作数是 NaN,返回 true;
如果操作数是 undefined,返回 true。
2.逻辑与:逻辑与操作符由两个和号(&&)表示,有两个操作数。
逻辑与操作可以应用于任何类型的操作数,而不仅仅是布尔值。在有一个操作数不是布尔值的情况下,逻辑与操作就不一定返回布尔值;此时,它遵循下列规则:
- 如果第一个操作数是对象,则返回第二个操作数;
- 如果第二个操作数是对象,则只有在第一个操作数的求值结果为 true 的情况下才会返回该对象;
- 如果两个操作数都是对象,则返回第二个操作数;
- 如果有一个操作数是 null,则返回 null;
- 如果有一个操作数是 NaN,则返回 NaN;
- 如果有一个操作数是 undefined,则返回 undefined。
逻辑与操作属于短路操作,即如果第一个操作数能够决定结果,那么就不会再对第二个操作数求值。
3.逻辑或:逻辑或操作符由两个竖线符号(||)表示,有两个操作数。
与逻辑与操作相似,如果有一个操作数不是布尔值,逻辑或也不一定返回布尔值;此时,它遵循下列规则: - 如果第一个操作数是对象,则返回第一个操作数;
- 如果第一个操作数的求值结果为 false,则返回第二个操作数;
- 如果两个操作数都是对象,则返回第一个操作数;
- 如果两个操作数都是 null,则返回 null;
- 如果两个操作数都是 NaN,则返回 NaN;
- 如果两个操作数都是 undefined,则返回 undefined。
与逻辑与操作符相似,逻辑或操作符也是短路操作符。也就是说,如果第一个操作数的求值结果为true,就不会对第二个操作数求值了。
3.乘性操作符
ECMAScript 定义了 3 个乘性操作符:乘法、除法和求模。
1.乘法:乘法操作符由一个星号(*)表示。
在处理特殊值的情况下,乘法操作符遵循下列特殊的规则:
- 如果操作数都是数值,执行常规的乘法计算,即两个正数或两个负数相乘的结果还是正数,而如果只有一个操作数有符号,那么结果就是负数。如果乘积超过了 ECMAScript 数值的表示范围,则返回 Infinity 或-Infinity;
- 如果有一个操作数是 NaN,则结果是 NaN;
- 如果是 Infinity 与 0 相乘,则结果是 NaN;
- 如果是 Infinity 与非 0 数值相乘,则结果是 Infinity 或-Infinity,取决于有符号操作数的符号;
- 如果是 Infinity 与 Infinity 相乘,则结果是 Infinity;
- 如果有一个操作数不是数值,则在后台调用 Number()将其转换为数值,然后再应用上面的规则。
2.除法:除法操作符由一个斜线符号(/)表示。
与乘法操作符类似,除法操作符对特殊的值也有特殊的处理规则。这些规则如下: - 如果操作数都是数值,执行常规的除法计算,即两个正数或两个负数相除的结果还是正数,而如果只有一个操作数有符号,那么结果就是负数。如果商超过了ECMAScript 数值的表示范围,则返回 Infinity 或-Infinity;
- 如果有一个操作数是 NaN,则结果是 NaN;
- 如果是 Infinity 被 Infinity 除,则结果是 NaN;
- 如果是零被零除,则结果是 NaN;
- 如果是非零的有限数被零除,则结果是 Infinity 或-Infinity,取决于有符号操作数的符号;
- 如果是 Infinity 被任何非零数值除,则结果是 Infinity 或-Infinity,取决于有符号操作数的符号;
3.求模:求模(余数)操作符由一个百分号(%)表示,用法如下:
var result = 26 % 5; // 等于 1
与另外两个乘性操作符类似,求模操作符会遵循下列特殊规则来处理特殊的值: - 如果操作数都是数值,执行常规的除法计算,返回除得的余数;
- 如果被除数是无穷大值而除数是有限大的数值,则结果是 NaN;
- 如果被除数是有限大的数值而除数是零,则结果是 NaN;
- 如果是 Infinity 被 Infinity 除,则结果是 NaN;
- 如果被除数是有限大的数值而除数是无穷大的数值,则结果是被除数;
- 如果被除数是零,则结果是零;
- 如果有一个操作数不是数值,则在后台调用 Number()将其转换为数值,然后再应用上面的规则。
4.加性操作符
1.加法:加法操作符(+)
如果两个操作符都是数值,执行常规的加法计算,然后根据下列规则返回结果:
- 如果有一个操作数是 NaN,则结果是 NaN;
- 如果是 Infinity 加 Infinity,则结果是 Infinity;
- 如果是-Infinity 加-Infinity,则结果是-Infinity;
- 如果是 Infinity 加-Infinity,则结果是 NaN;
- 如果是+0 加+0,则结果是+0;
- 如果是-0 加-0,则结果是-0;
- 如果是+0 加-0,则结果是+0。
不过,如果有一个操作数是字符串,那么就要应用如下规则: - 如果两个操作数都是字符串,则将第二个操作数与第一个操作数拼接起来;
- 如果只有一个操作数是字符串,则将另一个操作数转换为字符串,然后再将两个字符串拼接起来。
如果有一个操作数是对象、数值或布尔值,则调用它们的 toString()方法取得相应的字符串值,然后再应用前面关于字符串的规则。对于 undefined 和 null,则分别调用 String()函数并取得字符串"undefined"和"null"。
5.关系操作符
小于(<)、大于(>)、小于等于(<=)和大于等于(>=)这几个关系操作符用于对两个值进行比较,这几个操作符都返回一个布尔值。
与 ECMAScript 中的其他操作符一样,当关系操作符的操作数使用了非数值时,也要进行数据转换或完成某些奇怪的操作。以下就是相应的规则。
- 如果两个操作数都是数值,则执行数值比较。
- 如果两个操作数都是字符串,则比较两个字符串对应的字符编码值。
- 如果一个操作数是数值,则将另一个操作数转换为一个数值,然后执行数值比较。
- 如果一个操作数是对象,则调用这个对象的 valueOf()方法,用得到的结果按照前面的规则执行比较。如果对象没有 valueOf()方法,则调用 toString()方法,并用得到的结果根据前面的规则执行比较。
- 如果一个操作数是布尔值,则先将其转换为数值,然后再执行比较。
如果那个字符串不能被转换成一个合理的数值呢?比如:var result = "a" < 3; // false
,因为"a"被转换成了 NaN,由于字母"a"不能转换成合理的数值,因此就被转换成了 NaN。根据规则,任何操作数与 NaN 进行关系比较,结果都是 false。
6.相等操作符
ECMAScript 提供两组操作符:相等和不相等——先转换再比较,全等和不全等——仅比较而不转换。
1. 相等和不相等:
null 和 undefined 是相等的,即null == undefined // 返回true
。
2.全等和全不等:
null === undefined 会返回 false,因为它们是不同类型的值。
7.条件操作符
variable = boolean_expression ? true_value : false_value;
8.赋值操作符
就是等号 =
9.逗号操作符
在用于赋值时,逗号操作符总会返回表达式中的最后一项,如下面的例子所示:var num = (5, 1, 4, 8, 0); // num 的值为 0