关于js按位左移运算符 <<

462 阅读1分钟

参考

  1. developer.mozilla.org/zh-CN/docs/…
  2. cnodejs.org/topic/5bbd9…
  3. juejin.cn/post/690071…
  4. fengmumu1.github.io/2018/06/30/…

用法

按位左移运算符 <<,用法 a << b,意思是将a的二进制形式向左移动b(b < 32)个比特位,左边超出的位数会被清除,右边会被补零。

举例

9 << 2 得出36(9*2^2)

9(十进制): 00000000000000000000000000001001 (二进制)
9 << 2(十进制): 00000000000000000000000000100100 (二进制) = 36 (十进制)

得出结论:任意数字x移动至左边y位,得出 x2yx*2^y

工作案例

动画数据中有一个挂载层,挂载层上记录了多个挂载点,每个挂在点都可以显示隐藏,为了最大限度减小数据体积。用二进制的方式记录挂载点的显隐信息(visible)。

初始visible: 000000000000000000000000000000 (二进制) = 0
第0个挂载点显示: 1 << 0: 000000000000000000000000000001 (二进制)
增加一个挂载点后的visible1(visible | 1 << 0 ): 000000000000000000000000000001 (二进制) = 1
第1个挂载点显示: 1 << 1: 000000000000000000000000000010 (二进制)
增加两个挂载点后的visible2(visible1 | 1 << 1): 000000000000000000000000000011 (二进制) = 3

依此类推

问题

今天遇到一个bug,当挂载点超过30个,保存第31个挂载点的时候,visible信息错了。1 << 31 = -2147483648。

原因

Js 是按64位浮点数存储和表示数字的,能表示整数范围是 -2^53 - 2^53

是所有的按位操作符的操作数都会被转成补码形式的有符号32位整数。最左边的比特位为符号位(sign bit)。

解决方案

使用BigInt,同样可以使用除>>> (无符号右移)的操作符

BigInt 是一种内置对象,它提供了一种方法来表示大于 2^53 - 1 的整数。这原本是 Javascript中可以用 Number 表示的最大数字。BigInt 可以表示任意大的整数。

1n << 31n 得 2147483648n

BigInt("1") << 31n