位运算符用于直接对二进制位进行计算,一共有7个。运算符直接处理每一个比特位(bit),所以是非常底层的运算,好处是速度极快,缺点是很不直观,许多场合不能使用它们,否则会使代码难以理解和查错。
位运算符只对整数起作用,如果一个运算子不是整数,会自动转为整数后再执行。另外,虽然在 JavaScript 内部,数值都是以64位浮点数的形式储存,但是做位运算的时候,是以32位带符号的整数进行运算的,并且返回值也是一个32位带符号的整数。
在计算机内,有符号数有3种表示法:原码、反码和补码。
所谓原码就是二进制定点表示法,即最高位为符号位,“0”表示正,“1”表示负,其余位表示数值的大小。
反码表示法规定:正数的反码与其原码相同;负数的反码是对其原码逐位取反,但符号位除外。
补码表示法规定:正数的补码与其原码相同;负数的补码是在其反码的末位加1。
注: 位运算时,是先转为补码再进行运算的。
按位与&
&&运算符我们都知道,只有两个都为真,结果才为真。&道理是一样的,同位都为1,才返回1。例如1和3的按位与操作, 1 & 3 = 1 。
00000000 00000000 00000000 00000001
00000000 00000000 00000000 00000011
& -----------------------------------
00000000 00000000 00000000 00000001
复制代码
通常我们判断一个数字是奇数还是偶数,我们会通过取余
function assert(n) {
if (n % 2 === 1) {
console.log("n是奇数");
} else {
console.log("n是偶数");
}
}
assert(3); // "n是奇数"
复制代码
我们也可以用一个数和1进行按位&操作来判断,而且速度更快:
function assert(n) {
if (n & 1) {
console.log("n是奇数");
} else {
console.log("n是偶数");
}
}
assert(3); // "n是奇数"
复制代码
按位或|
||运算符我们都知道,只要有个一个为真,结果就为真。|的道理也是一样的,同位都一个为1,就返回1。例如1和3的按位或操作, 1 | 3 = 3 。
00000000 00000000 00000000 00000001
00000000 00000000 00000000 00000011
| -----------------------------------
00000000 00000000 00000000 00000011
复制代码
按位非~
按位取反,例如 ~1 = -2。
00000000 00000000 00000000 00000001 // 1 的补码
~ -----------------------------------
11111111 11111111 11111111 11111110 // -2 的补码
10000000 00000000 00000000 00000010 // 因为是负数,反码后末位+1,得到-2的原码
复制代码
按位异或^
同位只有一个为1才返回1,其余返回0。例如,1 ^ -3 = -4。
00000000 00000000 00000000 00000001
10000000 00000000 00000000 00000011
11111111 11111111 11111111 11111101
^ -----------------------------------
11111111 11111111 11111111 11111100 // -4 的补码
10000000 00000000 00000000 00000100 // -4 的原码
复制代码
有符号左移<<
符号位不动,其余补0;
8 << 2 = 32
00000000 00000000 00000000 00001000
-----------------------------------
00000000 00000000 00000000 00100000
复制代码
-2 << 1 = -4
10000000 00000000 00000000 000000010 // -2 原码
11111111 11111111 11111111 111111110 // -2 补码
------------------------------------
11111111 11111111 11111111 111111100 // -4 补码
10000000 00000000 00000000 000000100 // -4 原码
复制代码
有符号右移>>
符号位不动,正数补0,负数补1;
-2 >> 1 = -1;
10000000 00000000 00000000 000000010
11111111 11111111 11111111 111111110
------------------------------------
11111111 11111111 11111111 111111111
10000000 00000000 00000000 000000001 // -1
复制代码
无符号右移>>>
符号位也会移动,高位补0;
-2 >>> 2 =
10000000 00000000 00000000 00000010 // -2 原码
11111111 11111111 11111111 11111110 // -2 补码
-----------------------------------
00111111 11111111 11111111 11111111 // 1073741823 原码
复制代码
如果你有什么位运算的妙用,可以在评论里分享一下:)