ECMA-262描述了一组用于操作数据值的操作符,包括 算术操作符(如加号和减号)、位操作符、关系操作符和相等操作符。ECMAScript操作符的与众不同之处在于,它能够适用于很多值,例如字符串、数字值、布尔值、甚至对象。不过在应用于对象之前,相应的操作符通常会调用对象的valueOf()和(或)toString()方法,以便取得可以操作的值。
位操作符
位操作符用于在最基本的层次上,即按照内存中表示数值的位来操作数值。ECMAScript中的所有数值都以 IEEE-754 64位格式存储,但是位操作符并不直接操作64位,而是先将64位的值转换成32位的整数,然后执行操作,然后再将结果转换回64位。对于开发人员来说,由于64位存储格式是透明的,因此整个过程就像是只存在32位的整数一样。
对于有符号的整数,32位中的前31位用于表示整数的值。第32位用于表示整数的符号:0表示正数,1表示负数。这个表示符号的位叫做符号位,符号位的值决定了其他位数值的格式。其中,正数以纯二进制格式存储,31位中的每一位都表示2的幂。
负数同样以二进制存储,但使用的是二进制补码。计算一个数值的二进制补码,需要经过下列三个步骤:
1.求这个数值绝对值的二进制码(例如:要求 -18的二进制码,先求18的二进制码)
2.求二进制反码,即将 0 替换成 1,1替换成0
3.得到的二进制反码加1
ECMAScript会尽力向我们隐藏这些信息。换句话说,在以二进制字符串形式输出一个负数时,我们看到的只是这个负数绝对值的二进制码前面加上了一个负号。如:
var num = -18console.log(num.toString(-2)) // "-10010"
1. 按位非(NOT)
按位非操作符由一个波浪线(~)表示,执行按位非的结果就是返回数值的反码。按位非时ECMAScript操作符中少数几个与二进制计算有关的操作符之一。
var num1 = 25; //二进制 00000000000000000000000000011001var num2 = -num1; //二进制 111111111111111111111111100110console.log(num2); //-26
这里对25执行按位非操作,结果得到了-26,。这也验证了按位非操作的本质:操作数的负数减1。因此下面的代码也能得到相同的结果:
var num1 = 25;var num2 = -num1 - 1;console.log(num2) // -26
虽然以上代码也能返回同样的结果,但由于按位非是在数值表示的底层执行操作,因此速度更快。
2. 按位与(AND)
按位与操作符由一个和字符号(&)表示,它有两个操作符数。从本质上讲,按位与操作符就是将两个数值的每一位对齐,然后根据下表中的规则,对相应位置上两个数执行AND操作:
第一个数值的位 | 第二个数值的位 | 结果 |
---|---|---|
1 | 1 | 1 |
1 | 0 | 0 |
0 | 1 | 0 |
0 | 0 | 0 |
简而言之,按位与操作只在两个数值的对应位都是1时才返回1,任何一位是0,结果都是0。
3. 按位或(OR)
按位或操作符由一个竖线符号(|)表示,同样也有两个操作数。按位或操作遵循下面这个真值表。
第一个数值的位 | 第二个数值的位 | 结果 |
---|---|---|
1 | 1 | 1 |
1 | 0 | 1 |
0 | 1 | 1 |
0 | 0 | 0 |
由此可见,按位或操作在有一位是1的情况下就返回1,而只有在两个位都是0的情况下才会返回0。
4. 按位异或(XOR)
按位异或操作符由一个插入符号(^)表示,也有两个操作数。以下是按位异或的真值表。
第一个数值的位 | 第二个数值的位 | 结果 |
---|---|---|
1 | 1 | 0 |
1 | 0 | 1 |
0 | 1 | 1 |
0 | 0 | 0 |
按位异或 与 按位或的不同之处在于,这个操作符在两个数值对应位上只有一个1时才会返回1。
5. 左移
左移由两个小于号(<<)表示,这个操作符会将数值的所有位向左移动指定的位数。例如:如果将数值2(二进制码为10)向左移动5位,结果就是64(二进制码位 1000000)
注意,在向左移动后,原数值的右侧多出来5个空位。左移操作会以0来填充这些空位,以便得到的结果是一个完整的32位二进制数。
左移操作不会影响操作数的符号位,换句话说,如果将 -2 向左移动5位,得到的将是 -64,而不是64。
6. 有符号的右移
有符号的右移操作符由两个大于号(>>)表示,这个操作符会将数值向右移动,但保留符号位(即正负号标记)。
在移动过程中,原数值中也会出现空位,只不过这次空位出现在原数值的左侧、符号位的右侧。而此时ECMAScript会用符号位的值来填充所有空位,以便得到一个完整的值。
7. 无符号的右移
无符号右移操作符由三个大于号(>>>)表示,这个操作符会将数值的所有32位都向右移动。对于正数来说,无符号右移的结果与有符号右移相同。
但是对于负数来说,情况就不一样了。首先,无符号右移是以0来填充空位,而不是像有符号右移那样以符号位的值来填充空位。其次,无符号右移会把负数的二进制码当成正数的二进制码。而且由于负数以其绝对值的二进制码表示,因此就会导致无符号右移后的结果非常之大。