在Javascript中做什么~~(“双波浪”)?

What does ~~ (“double tilde”) do in Javascript?

我今天正在查看一个在线游戏物理库,遇到了~~接线员。我知道一个~,是一个位非,这会使~ ~,一个非,它会返回相同的值,不是吗?


它删除小数点后的所有内容,因为位运算符将其操作数隐式转换为带符号的32位整数。无论操作数是(浮点)数字还是字符串,结果都是数字。

换句话说,它产生:

1
2
3
4
function(x) {
  if(x < 0) return Math.ceil(x);
  else return Math.floor(x);
}

仅当x在(231)和231-1之间时。否则,将发生溢出,数字将"环绕"。

这对于将函数的字符串参数转换为数字可能很有用,但由于溢出的可能性以及它不适合与非整数一起使用,因此除了"代码高尔夫"(即无意义地从程序源代码中删去字节,以牺牲可读性和稳健性)之外,我不会以这种方式使用它。我会用+xNumber(x)代替。

这是怎么回事?

例如,数字-43.2是:

-43.210 = 111111111111111111111111110101012

作为有符号(2的补码)的32位二进制数。(javascript忽略小数点后的内容。)反转位可以得到:

NOT -4310 = 000000000000000000000000001010102 = 4210

再次反转可得出:

NOT 4210 = 111111111111111111111111110101012 = -4310

这与Math.floor(-43.2)的不同之处在于,负数四舍五入为零,而不是远离零。(floor函数等于-44,总是向下取整到下一个较低的整数,而不管数字是正数还是负数。)


第一个~运算符将操作数强制为整数(可能是在将值强制为字符串或布尔值之后),然后反转最低的31位。官方的ecmascript数字都是浮点数,但有些数字在spidermonkey引擎中实现为31位整数。

可以使用它将一个元素数组转换为整数。浮点数根据C规则转换,即小数部分的截断。

然后,第二个~运算符将位反转回来,这样您就知道您将得到一个整数。这与在条件语句中将值强制为布尔值不同,因为空对象的计算结果为true,而~的计算结果为false。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
js>~~"yes"
0
js>~~3
3
js>~~"yes"
0
js>~~false
0
js>~~""
0
js>~~true
1
js>~~"3"
3
js>~~{}
0
js>~~{a:2}
0
js>~~[2]
2
js>~~[2,3]
0
js>~~{toString: function() {return 4}}
4
js>~~NaN
0
js>~~[4.5]
4
js>~~5.6
5
js>~~-5.6
-5


在ecmascript 6中,等效于~~的是math.trunc:

Returns the integral part of a number by removing any fractional digits. It does not round any numbers.

1
2
3
4
5
6
7
8
Math.trunc(13.37)   // 13
Math.trunc(42.84)   // 42
Math.trunc(0.123)   //  0
Math.trunc(-0.123)  // -0
Math.trunc("-1.123")// -1
Math.trunc(NaN)     // NaN
Math.trunc("foo")   // NaN
Math.trunc()        // NaN

聚填料:

1
2
3
function trunc(x) {
    return x < 0 ? Math.ceil(x) : Math.floor(x);
}


~似乎与-(N+1)有关。所以,如果你在-3上再做一次,它就会把它变回原来的样子:~-3 == -(-3 + 1) == 2,它可能只是把一个字符串转换成一个圆形的数字。

请参阅此线程:http://www.sitepoint.com/forums/showthread.php?t=663275

此外,更多详细信息可从以下网址获得:http://dreaminginjavascript.wordpress.com/2008/07/04/28/


如果~N-(N+1),那么~~N就是-(-(N+1) + 1)。很明显,这会带来一个巧妙的技巧。


只是一点警告。这里的其他答案给我带来了一些麻烦。

其目的是删除浮点数小数点后的任何内容,但它有一些角情况,这会造成错误风险。我建议避免~~。

首先,~~不适用于非常大的数字。

~~1000000000000 == -727279968

作为替代方案,使用Math.trunc()(如gajus所述,Math.trunc()返回浮点数的整数部分,但仅在符合ecmascript 6的javascript中可用)。通过这样做,您可以为非ECMAScript-6环境制作自己的Math.trunc()

1
2
3
4
5
if(!Math.trunc){
    Math.trunc = function(value){
        return Math.sign(value) * Math.floor(Math.abs(value));
    }
}

我写了一篇关于这个的博客文章供参考:http://bitlords.blogspot.com/2016/08/the-double-tilde-x-technology-in.html


将字符串转换为数字

1
2
3
4
5
6
7
8
console.log(~~-1);    // -1
console.log(~~0);     // 0
console.log(~~1);     // 1
console.log(~~"-1");  // -1
console.log(~~"0");   // 0
console.log(~~"1");   // 1
console.log(~~true);  // 1
console.log(~~false); // 0

1是0

1
2
3
4
5
if (~someStr.indexOf("a")) {
  // Found it
} else  {
  // Not Found
}

来源


下面是如何有效地使用此运算符的示例,其中使用它是有意义的:

4

来源:

参见与点交互部分


tilde(~)有一个algorihm-(n+1)

例如:

1
2
3
~0 = -(0+1) = -1
~5 = -(5+1) = -6
~-7 = -(-7+1) = 6

双颚化符是-(-(n+1)+1)

例如:

1
2
~~5 = -(-(5+1)+1) = 5
~~-3 = -(-(-3+1)+1) = -3

三颚化符是-(-(-(n+1)+1)+1)

例如:

1
2
~~~2 = -(-(-(2+1)+1)+1) = -3
~~~3 = -(-(-(3+1)+1)+1) = -4