JavaScript 使用 32 位按位运算数。
JavaScript 将数字存储为 64 位浮点数,但所有按位运算都以 32 位二进制数执行。
在执行位运算之前,JavaScript 将数字转换为 32 位有符号整数。
执行按位操作后,结果将转换回 64 位 JavaScript 数。
<< 零填充左位移 通过从右推入零向左位移,并使最左边的位脱落。
>> 有符号右位移 通过从左推入最左位的拷贝来向右位移,并使最右边的位脱落。
>>> 零填充右位移 通过从左推入零来向右位移,并使最右边的位脱落。
“<<”运算符
<<
运算符执行左移位运算。在移位运算过程中,符号位始终保持不变。如果右侧空出位置,则自动填充为 0;超出 32 位的值,则自动丢弃。
例:把数字 5 向左移动 2 位,则返回值为 20。
console.log(5<<2); // 20
“>>”运算符
>>
运算符执行有符号右移位运算。与左移运算操作相反,它把 32 位数字中的所有有效位整体右移,再使用符号位的值填充空位。移动过程中超出的值将被丢弃。
例:把数值 1000 向右移 8 位,则返回值为 3。
console.log(1000>>8); // 3
例:把数值 -1000 向右移 8 位,则返回值为 -4。
console.log(-1000>>8); // -4
用算式进行演示,如图上所示。当符号位值为 1 时,则有效位左侧的空位全部使用 1 进行填充。
“>>>”运算符
>>>
运算符执行无符号右移位运算。它把无符号的 32 位整数所有数位整体右移。对于无符号数或正数右移运算,无符号右移与有符号右移运算的结果是相同的。
console.log(1000 >> 8); //返回值3
console.log(1000 >> 8); //返回值3
对于负数来说,无符号右移将使用 0 来填充所有的空位,同时会把负数作为正数来处理,所得结果会非常大。
console.log(-1000 >> 8); //返回值 -4
console.log(-1000 >>> 8); //返回值 16777212
如图上所示。左侧空位不再用符号位的值来填充,而是用 0 来填充。
应用场景举例
我们根据订阅-发布模式在写EventBus的时候,会写到一个off的删除方法。
off(type, handler) {
if (this.eventMap[type]) {
this.eventMap[type].splice(this.eventMap[type].indexOf(handler) >>> 0, 1);
}
}
这里为什么要使用>>>
呢?
考虑 indexOf 返回-1 的情况:splice方法喜欢把-1解读为当前数组的最后一个元素,这样子的话,在压根没有对应函数可以删的情况下,不管三七二十一就把最后一个元素给干掉了。而 >>> 符号对正整数没有影响,但对于-1来说它会把-1转换为一个巨大的数(你可以本地运行下试试看,应该是一个32位全是1的二进制数,折算成十进制就是 4294967295)。这个巨大的索引splice是找不到的,找不到就不删,于是一切保持原状,刚好符合我们的预期。