!!〜(不是波浪线/爆炸波浪线)如何改变“包含/包含” Array方法调用的结果?


95

如果您在此处的jQuery inArray页面上阅读了注释,则会有一个有趣的声明:

!!~jQuery.inArray(elm, arr) 

现在,我相信双感叹号会将结果转换为type boolean,其值为true。我不明白的是,~在所有这些中,tilde()运算符的用途是什么?

var arr = ["one", "two", "three"];
if (jQuery.inArray("one", arr) > -1) { alert("Found"); }

重构if语句:

if (!!~jQuery.inArray("one", arr)) { alert("Found"); }

分解:

jQuery.inArray("one", arr)     // 0
~jQuery.inArray("one", arr)    // -1 (why?)
!~jQuery.inArray("one", arr)   // false
!!~jQuery.inArray("one", arr)  // true

我还注意到,如果将波浪号放在前面,结果是-2

~!!~jQuery.inArray("one", arr) // -2

我不明白这里的波浪符号的目的。有人可以解释一下还是将我指向资源?


50
谁愿意编写这样的代码,都需要远离键盘。
Kirk Woll '02

12
@KirkWoll:为什么?~jQuery.inArray()实际上是非常有用的-甚至可能是搜索功能-1因失败而返回的唯一很好的理由(唯一的二进制补码是虚假的)。一旦您了解并理解了窍门,我觉得它比更具可读性!= -1
阿玛丹

9
@Amadan-不 就是不行。说真的,我简直不敢相信你!!~任何事情辩护。
Kirk Woll '02

24
问题是,这仅仅是一个“把戏”。if (x != -1)if (~x)我之间的主要区别在于,前者实际上表达了您打算做的事情。后者表示您想完全做其他事情(“请将我的64位数字转换为32位整数,并检查该整数的按位非”是否为真”),在这种情况下,您恰巧获得了预期的结果一种情况。
JimmiTh '02

10
>= 0可能还不够,所以使用了更多的神秘性!!~
Yoshi 2012年

Answers:


56

波浪号运算符实际上根本不是jQuery的一部分-在JavaScript本身中是按位NOT运算符。

参见波浪号大奥秘(〜)

您在实验中得到了奇怪的数字,因为您正在对整数执行按位逻辑运算(就我所知,整数可能存储为二进制补码或类似的数字...)

二进制补码说明了如何用二进制表示数字。我想我是对的。


3
固定!(奇怪的是,将其更改为另一个链接,该链接是在我最初的答案之后写的...)
pglhall

121

有一个特定的原因有时会~导致您在前面看到它$.inArray

基本上,

~$.inArray("foo", bar)

是一种较短的方法

$.inArray("foo", bar) !== -1

$.inArray如果找到第一个参数,则返回数组中该项的索引,如果找不到第一个参数,则返回-1。这意味着,如果您要查找“此值是否在数组中?”的布尔值,则不能进行布尔值比较,因为-1是真实值,并且$ .inArray返回0(错误值) ),则表示其实际位于数组的第一个元素中。

应用~按位运算符导致-1变为0,并使0变为`-1。因此,在数组中找不到该值并应用按位NOT不会得出虚假的值(0),其他所有值将返回非0的数字,并表示真实结果。

if (~$.inArray("foo", ["foo",2,3])) {
    // Will run
}

它会按预期工作。


2
它在浏览器中的支持程度如何(现在是2014年?)还是一直以来都得到完美的支持?
爆炸药

如果像这样的基本操作不完美,我会感到惊讶。
pcarvalho 2015年

104

!!~expr计算结果为false,当expr-1,否则true
与相同expr != -1,仅损坏*


之所以有效,是因为JavaScript按位运算将操作数转换为二进制补码格式的32位有符号整数。因此!!~-1,评估如下:

   -1 = 1111 1111 1111 1111 1111 1111 1111 1111b // two's complement representation of -1
  ~-1 = 0000 0000 0000 0000 0000 0000 0000 0000b // ~ is bitwise not (invert all bits)
   !0 = true                                     // ! is logical not (true for falsy)
!true = false                                    // duh

以外的值-1将至少一位设置为零;否则为0。反转它会产生一个真实的价值;将!运算符两次应用于真实值将返回布尔值true。

当与一起使用时.indexOf(),我们只想检查结果是否为-1

!!~"abc".indexOf("d") // indexOf() returns -1, the expression evaluates to false
!!~"abc".indexOf("a") // indexOf() returns  0, the expression evaluates to true
!!~"abc".indexOf("b") // indexOf() returns  1, the expression evaluates to true

* !!~8589934591评估为假,因此厌恶无法可靠地用于测试-1


1
在稳定的库中,我看不到使用~foo.indexOf(bar),这在字符或性能上没有显着的节省,但是在相同的方式下,它是一个相对常见的速记foo = foo || {}
zzzzBov 2012年

6
这不是问题,至少在要求其他人继续执行您的代码之前是没有问题的。
Salman A


1
@ahsteele,我很清楚该规则,但是按位运算符是我能想到的每种编程语言的一部分。我尝试以一种可以读取代码的人可读的方式进行编程。我不会仅仅因为别人听不懂它而停止使用某种语言的功能,否则我什至无法使用!!
zzzzBov 2012年

严格来说,>= 0与的行为不同!!~!== -1更近。
彼得·奥尔森

33

~foo.indexOf(bar)是常见的简写形式,foo.contains(bar)因为该contains函数不存在。

通常,由于JavaScript的“虚假”值概念,强制转换为布尔值是不必要的。在这种情况下,它用于强制函数的输出为trueor false


6
+1此答案比接受的答案更好地解释了“为什么”。
2012年

18

jQuery.inArray()返回-1“未找到”,其补数(~)为0。因此,对于“未找到” ,~jQuery.inArray()返回虚假值(0),对于“发现”,返回真实值(负整数)。!!然后将虚假/真实的形式化为真正的布尔值false/ true。因此,!!~jQuery.inArray()将给予true“找到”和false“未找到”。



10

~运算符是按位补码运算符。inArray()当找不到元素时,的整数结果为-1或一些非负整数。-1的按位补码(以二进制形式表示为全部1位)为零。任何非负整数的按位补码始终为非零。

因此,当整数“ i”是一个非负整数,而当“ i”正好为-1 时,!!~i将为。truefalse

注意,~始终将其操作数强制为整数;也就是说,它将非整数浮点值强制为整数以及非数字值。


10

波浪号不是按位的-它将值的每一位取反。一般而言,如果您使用~数字,则其符号将被反转,然后将其减去1。

因此,当你做 ~0,您会得到-1(0取反是-0,减1则是-1)。

从本质上讲,这是获取始终为布尔值的精巧,超微优化的方法。


8

您说对了:调用返回-1 false时,将返回此代码indexOf;除此以外true

正如您所说,使用类似

return this.modifiedPaths.indexOf(path) !== -1;

1
但这还有3个字节要发送给客户端!编辑:(顺便开个玩笑,发表我的评论,并意识到这并不明显(这既悲伤又愚蠢))
Wesley Murch,2012年

@Wesley:的确如此,但是假设客户端将缓存,它只需发送给每个客户端一次.js。话虽这么说,他们可以使用>=0而不是!==-1-没有额外的字节来发送,并且比位纠缠版本更具可读性。
路加福音

2
谁在这里拖谁?;)我想我认为理所当然的是,编写可读代码比生成此类问题的经过加密的预优化代码更好。请稍后再缩小并立即编写可读性强的代码。
Wesley Murch

2
就我个人而言,我认为它> -1更具可读性,但这可能是非常主观的。
Yoshi

6

~运算符是按位NOT运算符。这意味着它采用二进制形式的数字并将所有零变为一,而一个变为零。

例如,二进制中的数字0是0000000,而-1是11111111。同样,1为00000001二进制,而-2为二进制11111110


3

我的猜测是,它在那里是因为它短了几个字符(图书馆作者总是在后面几个字符)。当编译成本机代码时,它还使用仅花费几个机器周期的操作(而不是与数字进行比较)。

我同意另一个答案,认为这是一个过大的选择,但可能在一个紧密的循环中才有意义(不过,需要估算性能增益,否则可能是过早的优化。)


2

我认为,由于这是按位操作,因此它是检查路径是否出现在ModifyPaths中的最快方法(从计算上来说很便宜)。


1

作为(~(-1)) === 0,所以:

!!(~(-1)) === Boolean(~(-1)) === Boolean(0) === false

1
这也许是正确的,但这对发问者有用吗?一点也不。如果我一开始不理解,那么像这样的简洁答案将无济于事。
Spudley

我认为这个答案是有道理的。如果您具有数学头脑,则可以清楚地看到每个步骤中哪些部分正在更改。这是这个问题的最佳答案吗?不,但是它很有用,我认为是!+1
泰勒·洛佩兹
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.