如
MDN文档所述,我引用一下:
所有位运算符的操作数都被转换为二进制补码格式的有符号32位整数。
这意味着当您应用位运算符(例如
~
)到
2.1
时,它首先会被转换为整数,然后才应用运算符。这实际上实现了正数的向下取整(floor)效果。
至于为什么使用这些运算符,而不是更易理解的
Math.floor
,原因有两个。首先,这些运算符可能
相对较快地实现相同的结果。除了性能外,有些人只想要最短的代码。您提到的所有三个运算符都可以实现相同的效果,但
~~
恰好是最短的,也可以说是最容易记住的。
鉴于浮点数转整数发生在位运算符被应用之前,让我们看看使用
~~
会发生什么。为了简洁起见,我将使用8位来表示我们的目标数字(在从2.1转换后为2)。
2: 0000 0010
~2: 1111 1101 (-3)
~~2: 0000 0010
因此,你看,我们应用一个运算符来检索整数部分,但我们不能仅应用一个按位取反,因为它会破坏结果。我们通过应用第二个运算符将其恢复到所需的值。
关于您最后的例子,请注意您正在测试的数字2e + 21是一个相对较大的数字。它是由二十一个零组成的数字2。当您应用位运算符时,它无法适应32位整数(数据类型被转换为32位整数)。只需查看您的数字与32位有符号整数可以表示的内容之间的差异即可。
Max. Integer: 2147483647
2e+21: 2000000000000000000000
"二进制怎么样?"
Max. Integer: 01111111111111111111111111111111
2e+21: 11011000110101110010011010110111000101110111101010000000000000000000000
相当大,是吧?
实际上,在幕后发生的事情是Javascript将你的大数字
截断 为32位可以表示的数字。
110110001101011100100110101101110001011 10111101010000000000000000000000
^
当我们将被截断的数字转换成十进制数时,我们得到了你所看到的内容。
Bin: 10111101010000000000000000000000
Dec: -1119879168
相反,
Math.floor
考虑到大数并避免截断它们,这可能是它较慢但准确的原因之一。
~~
的适当位置。使用~~
而不是Math.floor(n)
的主要好处是它可以节省11个字符,这在任务是尽可能地编写短程序时是非常大的字节节省量。 - Compass