JS神奇的或0(|0)
按照常识,位运算x|0,要么等于x,要么等于0
那么在JS的世界你的认知就要被颠覆了
下面请看
不带或0运算: (window.crypto.getRandomValues(new Uint32Array(1))[0] * 0x10000 ) 168546249998336 (window.crypto.getRandomValues(new Uint32Array(1))[0] * 0x10000 ) 18707488702464 (window.crypto.getRandomValues(new Uint32Array(1))[0] * 0x10000 ) 15579009253376 (window.crypto.getRandomValues(new Uint32Array(1))[0] * 0x10000 ) 194841754140672 (window.crypto.getRandomValues(new Uint32Array(1))[0] * 0x10000 ) 262611854950400 (window.crypto.getRandomValues(new Uint32Array(1))[0] * 0x10000 ) 171394313420800 带或0运算: (window.crypto.getRandomValues(new Uint32Array(1))[0] * 0x10000 )|0 -1037238272 (window.crypto.getRandomValues(new Uint32Array(1))[0] * 0x10000 )|0 511180800 (window.crypto.getRandomValues(new Uint32Array(1))[0] * 0x10000 )|0 1204224000 (window.crypto.getRandomValues(new Uint32Array(1))[0] * 0x10000 )|0 -2026438656
可以看到明显的带或0运算与不带或0运算的结果无论是位数还是符号位都有不同。
那这中间到底发生了什么?
这里找一个数字为例:117063531626496
要想验证这个问题,思路如下:
1,对比变更前后的数字的二进制格式
2,找到是否有数字表示的安全边界
首先按照思路1,我们看一下这个数字和这个数字或0后的二进制格式分别是什么:
117063531626496的二进制格式: var num = 117063531626496; num.toString(2); 输出:'11010100111011111111010001110000000000000000000' 117063531626496 | 0 输出:-96993280 -96993280的二进制格式: var num = -96993280; num.toString(2); '-101110010000000000000000000'
对比对比:
11010100111011111111010001110000000000000000000 -101110010000000000000000000
除了后面的0位数相同,没有找到明显的线索
那么我们快讯按照思路2,来看一下原因:
通过官网对于js的number的定义,是64位的统一类型
但是我们通过 Number.MAX_SAFE_INTEGER可以看到number的安全最大值是:9007199254740991
通过转为2进制,可以发现这个数字是个54位的1: var num = 9007199254740991; num.toString(2) '11111111111111111111111111111111111111111111111111111'
那这个值可以正常地或0吗?实际上还是不行
9007199254740991|0 -1 9007199254740990|0 -2
那这个边界到底是多少呢?对于其它语言Integer的默认最大值一般为2的32次方-1,也就是2147483647
这次再来试一下:
2147483647|0 2147483647 如果对这个值再+1,重试呢 2147483648|0 -2147483648
可以发现这个边界就是32位整数的最大值。
超过这个值的数字再与0进行位运算则可能得到一个错误的结果。
分类: Javascript