# 1. 按位非 ~
对每一个比特位执行非(NOT)操作。NOT a 结果为 a 的反转(即反码)。
var num = ~4;
console.log(a); // -5
解析:
4 的二进制数为 100,补满32位
00000000000000000000000000000100
按位取反
11111111111111111111111111111011
由于32位开头第一个是 1,所以这是一个负数,将二进制转换成负数,需要先反码
00000000000000000000000000000100
之后,再+1
00000000000000000000000000000101
转换成十进制为 5,加上符号变成负数 -5
# 2. 按位与 &
对每对比特位执行与(AND)操作。只有 a 和 b 都是 1 时,a AND b 才是 1。
var num = 2 & 3;
console.log(num); // 2
解析:
2 的二进制数为 10,3 的二进制数为 11,补满 32 位分别为
2 = 00000000000000000000000000000010
3 = 00000000000000000000000000000011
按位 & 运算,结果为
00000000000000000000000000000010 = 2
# 3. 按位或 |
对每一对比特位执行或(OR)操作。如果 a 或 b 为 1,则 a OR b 结果为 1。
var num = 2 | 3;
console.log(num); // 3
解析:
2 的二进制数为 10,3 的二进制数为 11,补满 32 位分别为
2 = 00000000000000000000000000000010
3 = 00000000000000000000000000000011
按位 | 运算,结果为
00000000000000000000000000000011 = 3
# 4. 按位异或 ^
对每一对比特位执行异或(XOR)操作。当 a 和 b 不相同时,a XOR b 的结果为 1。
var num = 2^3;
console.log(num); // 1
解析:
2 的二进制数为 10,3 的二进制数为 11,补满 32 位分别为
2 = 00000000000000000000000000000010
3 = 00000000000000000000000000000011
按位 ^ 运算,结果为
00000000000000000000000000000001 = 1
# 5. 左移 <<
该操作符会将第一个操作数向左移动指定的位数。向左被移出的位被丢弃,右侧用 0 补充。
var num = 2<<1;
console.log(num); // 4
解析:
2 的二进制数为 10,补满 32 位
2 = 00000000000000000000000000000010
左移 1 位,结果为
00000000000000000000000000000100 = 4
**注意:**左移不会影响操作符的符号位,例如将 -2 左移 5 位就是 -64
# 6. 有符号右移 >>
该操作符会将第一个操作数向右移动指定的位数。向右被移出的位被丢弃,拷贝最左侧的位以填充左侧。由于新的最左侧的位总是和以前相同,符号位没有被改变。所以被称作“符号传播”。
var num = 9>>2;
console.log(num); // 2
解析:
2 的二进制数为 10,补满 32 位
9 = 00000000000000000000000000001001
右移 2 位,结果为
00000000000000000000000000000010 = 1
相比之下, -9 >> 2 得到 -3,因为符号被保留了:
-9 = 11111111111111111111111111110111
右移 2 位,结果为
11111111111111111111111111111101 = -3
# 7. 无符号右移 >>>
该操作符会将第一个操作数向右移动指定的位数。向右被移出的位被丢弃,左侧用0填充。因为符号位变成了 0,所以结果总是非负的。(注:即便右移 0 个比特,结果也是非负的。)
var num = 9>>>2;
console.log(num); // 2
解析:
对于非负数,有符号右移和无符号右移总是返回相同的结果。例如, 9 >>> 2 得到 2 和 9 >> 2 相同:
但是对于负数却不尽相同。 -9 >>> 2 产生 1073741821 这和 -9 >> 2 不同:
-9 = 11111111111111111111111111110111
无符号右移 2 位:
00111111111111111111111111111101 = 1073741821