雙位元非運算符(~~)- James Padolsey

內容

誰會想到 JavaScript 稀有而神秘的位元運算子竟然如此有用呢?我是從 Thomas Fuchs 的 JavaScript 效能投影片 中一個演示中,第一次發現這個技巧的。這個“技巧”如下:

位元補數運算子(~)將取其運算元,將其轉換為32位元整數,並將每個位元反轉,使每個 0 變為 1,反之亦然。

00000000000000000000000000001001 ...becomes 11111111111111111111111111110110

對於表達式~foo,其效果是-(foo + 1)。雙重位元非運算(~~foo)將導致-(-(foo + 1) + 1)。然而,這僅對整數成立;考慮到所有可能的運算元,~~的真正等效表達式可能是這樣的:

typeof foo === 'number' && !isNaN(foo) && foo !== Infinity ? foo > 0 ? Math.floor(foo) : Math.ceil(foo) : 0; // 這僅僅是_實際上_相同... 這不是內部發生的事情!

這顯然比~~慢得多。

如果運算元是一個數字且不是 NaNInfinity,則 ~~ 會將其向零捨入(對於負數使用 Math.ceil,對於正數使用 Math.floor)。如果不是數字,我相信內部的 ToInt32 函數會將其轉換為零。

這裡有一些雙位元非運算的精彩範例:

~~null; // => 0 ~~undefined; // => 0 ~~0; // => 0 ~~{}; // => 0 ~~[]; // => 0 ~~(1/0); // => 0 ~~false; // => 0 ~~true; // => 1 ~~1.2543; // => 1 ~~4.9; // => 4 ~~(-2.999); // => -2

~~ 的地板功能使其成為 Math.floor 的更好替代品,如果你知道你在處理正數的話 — 它更快且佔用的字元更少。不過可讀性沒有那麼好,但我希望 ~~ 會慢慢成為 JavaScript 領域中非常著名的技巧,這樣我們就可以放心地使用它,而不必擔心被指責。

這對於希望參數正規化為整數的情況非常有用。以MDC建議中提供Array.prototype.indexOf給不支援的瀏覽器為例:

總結
JavaScript中的雙位元非運算子(~~)可以將數字四捨五入至最接近的整數,並且比Math.floor更快且佔用較少字元。這個技巧對於正規化預期為整數的參數非常有用,並且可以取代一些數學運算。