JavaScript中使用IEEE-754 64位存储。位操做符不能直接操做64位的值,而是将它转换为二进制补码形式的32位的整数,最后再将结果转为64位。32位中31位表示整数的值,第32位为符号位(0为正数,1为负数)。每一位由二进制数存储,31位中的每一位的索引表示2的次幂乘与每一位的0或者1。没有使用到的位将使用0填充。javascript
举一个例子🌰。31的32位二进制数表示为0000 0000 0000 0000 0000 0000 0001 1111。第32位0表示符号位,11111为有效位。java
1 | 1 | 1 | 1 | 1 |
---|---|---|---|---|
2^4 * 1 | 2^3 * 1 | 2^2 * 1 | 2^1 * 1 | 2^0 * 1 |
16 | 8 | 4 | 2 | 1 |
负数使用二进制存储,可是使用二进制补码表示数组
如何求一个数的二进制补码?post
举一个例子🌰。如何求出-31
的二进制补码。-31的二进制补码的结果为1111 1111 1111 1111 1111 1111 1110 0001。性能
0000 0000 0000 0000 0000 0000 0001 1111
复制代码
1111 1111 1111 1111 1111 1111 1110 0000
复制代码
1111 1111 1111 1111 1111 1111 1110 0000
+1
---------------------------------------
1111 1111 1111 1111 1111 1111 1110 0001
复制代码
ECMAScript全部整数都是有符号位的。在无符号数中,第32位不表示符号,由于无符号数只能是正数,32位无符号数能够表示更大的数。spa
在NaN和Infinity在位运算符中会被看成0处理。非数值类型会先使用Number()
处理,而后再应用位操做符。设计
按位非
~
会将数值的32位二进制的每一位取反(0变为1,1变为0)。按位非的操做符的本质取操做数的负值,而后减一。3d
// -24
~23
// -101
~100
// 9
~-10
// 100
~-101
复制代码
举一个例子🌰。10进行按位非以后的结果,等于-11rest
0000 0000 0000 0000 0000 0000 0000 1010
// ~ NOT
1111 1111 1111 1111 1111 1111 1111 0101
复制代码
按位与&, 本质上将两个操做数的32位二进制数的每一位对齐。而后按以下的规则取值,1 & 1 等于 1; 1 & 0 等于 0;0 & 1 等于0;0 & 0等于0。code
举一个例子🌰。10和5之间进行按位与操做的结果,等于0
0000 0000 0000 0000 0000 0000 0000 1010
// & AND
0000 0000 0000 0000 0000 0000 0000 0101
// 等于
0000 0000 0000 0000 0000 0000 0000 0000
复制代码
按位与|, 本质上将两个操做数的32位二进制数的每一位对齐。而后按以下的规则取值,1 | 1 等于 1; 1 | 0 等于 1;0 | 1 等于1;0 | 0等于0。
举一个例子🌰。10和5之间进行按位或操做的结果,等于15
0000 0000 0000 0000 0000 0000 0000 1010
// & OR
0000 0000 0000 0000 0000 0000 0000 0101
// 等于
0000 0000 0000 0000 0000 0000 0000 1111
复制代码
按位异或^, 本质上将两个操做数的32位二进制数的每一位对齐。而后按以下的规则取值,1 ^ 1 等于 0; 1 ^ 0 等于 1;0 ^ 1 等于1;0 ^ 0等于0。
举一个例子🌰。10和5之间进行按位异或操做的结果15。
0000 0000 0000 0000 0000 0000 0000 1010
// ^ XOR
0000 0000 0000 0000 0000 0000 0000 0101
// 等于
0000 0000 0000 0000 0000 0000 0000 1111
复制代码
左移(<<)将32位二进制向左移动指定的位数,空缺的位将会使用0填充。左移不会影响符号位
举一个例子🌰。将5左移2位,等于20
0|000 0000 0000 0000 0000 0000 0000 0101
// <<2
0|000 0000 0000 0000 0000 0000 0001 0100
// 等于
(2^0 * 0) + (2^1 * 0) + (2^2 * 1) + (2^3 * 0) + (2^4 * 1) = 0 + 0 + 4 + 0 + 16 = 20
复制代码
右移(>>)将32位二进制向右移动指定的位数,可是保留符号位,右移空缺的符号位使用0填充
举一个例子🌰。将31有符号右移3位,等于3。
0|000 0000 0000 0000 0000 0000 0001 1111
// >>3
0|000 0000 0000 0000 0000 0000 0000 0011
// 等于
(2^0 * 1) + (2^1 * 1) = 1 + 2 = 3
复制代码
无符号位右移,会将全部32位数都向右移动。对于正数来讲右移和无符号位右移的结果是一致的。
举一个例子🌰。将-31无符号右移28位。
1111 1111 1111 1111 1111 1111 1110 0001
// >>> 28
0000 0000 0000 0000 0000 0000 0000 1111
// 等于
(2^0 * 1) + (2^1 * 1) + (2^2 * 1) + (2^3 * 1) = 1 + 2 + 4 + 8 = 15
复制代码
按位非~。将操做数取负值,并减1。对于浮点数,会直接舍弃小数的部分。好比
~11.1 === -12
。而后将结果,再次执行按位非操做,就会获得了去除小数位的原数字,~-12 === 11
。所以咱们可使用~~代替Math.floor。
// 12
~~12.5
// 6
~~6.1
// 8
~~-8.1
复制代码
我分别使用~~和Math.floor,对包含了10000000个浮点数的数组,进行向下取整。~~耗时386毫秒,Math.floor耗时411毫秒.
平时使用indexOf等API时,当查询的字符串不存在时,indexOf会返回-1。可是Boolean(-1)
等于true,因此咱们在使用时一般须要添加一个判断'字符串'.indexOf('字') > -1
,看上去并非那么的简洁。 -1按位非等于0,而Boolean(0)是等于false的。因此咱们能够把不等式简化成下面的样子。
if ('米莉波比布朗'.indexOf('莉') > -1) {
}
// 等价于
if (~'米莉波比布朗'.indexOf('莉')) {
}
复制代码
在了解这个技巧以前须要先了解两个准则:
// 0
100 ^ 100
// 0
-99 ^ -99
// 100
100 ^ 0
// -2
0 ^ -2
复制代码
在代码中交换两个变量的值,一般是经过第三个变量,或者使用ES6中的解构赋值
// 使用第三个变量
var a = 1
var b = 2
var c = a
a = b
b = c
// 使用解构赋值
var x = 1
var y = 2
[x, y] = [y, x]
复制代码
使用异或按位运算符
let a = 2
let b = 3
a = a ^ b
// b = a ^ b ^ b => a ^ (b ^ b) => a ^ 0 = a
b = a ^ b
// a = a ^ b ^ a ^ b ^ b => (a ^ a) ^ (b ^ b) ^ b => 0 ^ 0 ^ b => 0 ^ b = b
a = a ^ b
复制代码
使用异或按位运算符,能够用来切换二进制数中的某些位,这基于这样一个事实:
let a = 1
// 0
a = 1 ^ 1
// 1 (又变回了1)
a = a ^ 1
复制代码
举一个例子🌰,let a = 0b101011
, 咱们想将中间的四位进行切换(0->1, 1->0)变为0b110101
。咱们建立一个掩码,首尾为0,中间四位为1, 使用掩码进行按位异或的操做。
// 掩码
let mask = 0b011110
let a = 0b101011
// 0b110101
a ^ mask
复制代码
使用按位与&, 能够用来关闭二进制数中的某些位,这基于这样一个事实:
好比咱们有一个8位的二进制数,咱们须要关闭后4位(设置为0),咱们首先建立一个8位的位掩码,位掩码的后四位设置为0,前四位设置为1。接下来使用位掩码与操做数进行按位与操做
const mask = 0b00001111
// 结果00001010,成功将后四位设置为0
mask & 0b10101010
复制代码
可使用按位与,检查二进制数中某一位是否设置了。
举一个例子🌰,咱们须要检查第五位是否有数字。
const mask = 0b10000
// false
0b100010 & mask === mask
// true
0b110010 & mask) === mask)
复制代码
奇数与偶数的二进制表示的特性:
// 0b0
0
// 0b1
1
// 0b10
2
// 0b11
3
// 0b100
4
// 0b101
5
// 0b110
6
复制代码
因此咱们可使用0001做为掩码,使用0关闭高位,只保留第一位。当number & 1 === 1
, number为奇数。number & 1 === 0
, number为偶数。
// 奇数
(3 & 1) === 1
// 偶数
(4 & 1) === 0
复制代码
ps:😂在工程中,最好不要这样写,省得的被打。
左移1位,等于乘以2,左移2位,等于乘以4。可是对于乘以7或者乘以9该怎么办呢?乘以7,能够分解为左移3位并减去一位,
a * 7 === (a << 3) - a
。乘以9,能够分解为左移3位并加上一位a * 9 === (a << 3) + a
a * 2 === a << 1
a * 3 === (a << 1) + a
a * 4 === a << 2
复制代码
a / 2 === a >> 1
a / 4 === a >> 2
a / 8 === a >> 3
复制代码