按照常識,位運算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進行位運算則可能得到一個錯誤的結果。