双位非运算符 (~~) – 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的更好替代品,如果你知道你在处理正数——它更快,占用的字符更少。不过可读性不如Math.floor,但我希望~~会慢慢成为JS领域中非常知名的技巧,这样我们就可以放心地使用它,而不必担心被指责。

这里放翻译好的文字:它非常有用,可以将你期望为整数的参数进行规范化。以MDC建议中的示例为例,用于为不支持的浏览器提供Array.prototype.indexOf

/Array.prototype.indexOf = function.../ var from = Number(arguments[1]) || 0;
from = (from < 0)
? Math.ceil(from)
: Math.floor(from);

总结
JavaScript中的双位非操作符(~~)可以用于快速取整,对于数字类型的操作数,它会向零取整,对于非数字类型的操作数,它会转换为0。这种技巧可以用于规范化预期为整数的参数,也可以替代Math.floor进行取整操作,速度更快且字符更少。