!!~(不是波浪号/bang bang 波浪号)如何改变“包含/包含”数组方法调用的结果?
Posted
技术标签:
【中文标题】!!~(不是波浪号/bang bang 波浪号)如何改变“包含/包含”数组方法调用的结果?【英文标题】:How does !!~ (not not tilde/bang bang tilde) alter the result of a 'contains/included' Array method call? 【发布时间】:2012-03-08 03:58:49 【问题描述】:如果你阅读了 jQuery inArray
页面 here 上的 cmets,有一个有趣的声明:
!!~jQuery.inArray(elm, arr)
现在,我相信双感叹号会将结果转换为boolean
类型,其值为true
。我不明白的是,波浪号 (~
) 运算符在所有这些中的用途是什么?
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
我不明白波浪号的用途。有人可以解释一下或将我指向资源吗?
【问题讨论】:
写这样的代码的人需要离开键盘。 @KirkWoll:为什么?~jQuery.inArray()
实际上非常有用 - 甚至可能是搜索函数返回 -1
失败的一个很好的理由(唯一的二进制补码为假的值)。一旦你看到并理解了这个技巧,我觉得它比!= -1
更具可读性。
@Amadan -- 没有。就是不行。说真的,我不敢相信你会为 任何事情 为 !!~
辩护。
问题是,它只是:一个“把戏”。 if (x != -1)
和 if (~x)
对我来说的主要区别在于前者实际上表达了你打算做什么。后者表示您想要完全做其他事情(“请将我的 64 位数字转换为 32 位整数,并检查该整数的按位 NOT 是否为真”),而您恰好在此获得所需的结果一个案例。
>= 0
可能还不够 leet,所以使用了更神秘的!!~
。
【参考方案1】:
!!~expr
当expr
为-1
时计算为false
,否则为true
。
和expr != -1
一样,只是坏了*
之所以有效,是因为javascript bitwise operations 将操作数转换为二进制补码格式的 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
以外的值将至少有一位设置为零;反转它会创造一个真实的价值;将 !
运算符两次应用于真值返回布尔值 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
的计算结果为 false,因此这个 abomination 不能可靠地用于测试 -1
。
【讨论】:
在一个稳定的库中,我认为使用~foo.indexOf(bar)
没有问题,它不会显着节省字符或性能,但它是一种相对常见的简写方式,与foo = foo ||
相同。
这不是问题...至少在要求其他人继续使用您的代码之前不会。
@zzzzBov 到 expand on Salman's 评论:always code as if the person who ends up maintaining your code is a violent psychopath who knows where you live.
@ahsteele,我很清楚这条规则,但是按位运算符是我能想到的每种编程语言的一部分。我尝试以一种可以阅读代码的人可以阅读的方式进行编程。我不会因为别人不理解而停止使用语言的特性,否则我wouldn't even be able to use !!
。
严格来说,>= 0
的行为与!!~
不同。 !== -1
更近了。【参考方案2】:
我假设,因为它是按位运算,所以它是检查 path 是否出现在 modifiedPaths 中的最快(计算成本低)方法。
【讨论】:
【参考方案3】:波浪号运算符实际上根本不是 jQuery 的一部分 - 它是 JavaScript 本身中的按位 NOT 运算符。
见The Great Mystery of the Tilde(~)。
您在实验中得到奇怪的数字,因为您正在对整数执行按位逻辑运算(据我所知,它可能存储为二进制补码或类似的东西......)
Two's complement 解释了如何用二进制表示一个数字。我想我是对的。
【讨论】:
已修复! (将其更改为另一个链接,奇怪的是,它是在我原来的答案之后写的......)【参考方案4】:所有4个字节的~
int
等于这个公式-(N+1)
所以
~0 = -(0+1) // -1
~35 = -(35+1) // -36
~-35 = -(-35+1) //34
【讨论】:
这并不总是正确的,因为(例如)~2147483648 != -(2147483648 + 1)
。【参考方案5】:
您有时会看到 ~
应用在 $.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
它会按预期工作。
【讨论】:
浏览器对它的支持程度如何(现在是 2014 年?)还是一直完美支持? 如果像这样的基本操作不完美,我会感到惊讶。【参考方案6】:~foo.indexOf(bar)
是表示foo.contains(bar)
的常用简写,因为contains
函数不存在。
由于 JavaScript 的“虚假”值概念,通常不需要强制转换为布尔值。在这种情况下,它用于强制函数的输出为true
或false
。
【讨论】:
+1 这个答案比公认的答案更能解释“为什么”。【参考方案7】:作为(~(-1)) === 0
,所以:
!!(~(-1)) === Boolean(~(-1)) === Boolean(0) === false
【讨论】:
这可能是准确的,但它对提问者有用吗?一点也不。如果我一开始就不明白,那么像这样简洁的答案也无济于事。 我认为这个答案是有道理的。如果你有一个数学大脑,你可以清楚地看到每一步都有哪些部分在变化。这是对这个问题的最佳答案吗?不,但它很有用,我想是的! +1【参考方案8】:你是对的:当 indexOf
调用返回 -1 时,此代码将返回 false
;否则true
。
正如你所说,使用类似的东西会更明智
return this.modifiedPaths.indexOf(path) !== -1;
【讨论】:
但是要发送给客户端的还有 3 个字节!编辑:(顺便开玩笑,发表了我的评论并意识到这并不明显(既可悲又可笑)) @Wesley:没错,但它只需要发送给每个客户端一次,假设客户端将缓存.js
。话虽如此,他们可以使用>=0
而不是!==-1
- 无需发送额外的字节,并且比位旋转版本更具可读性。
谁在这里拖钓谁? ;) 我想我想当然地认为编写可读代码比生成这类问题的神秘预优化代码要好。稍后再缩小并立即编写可读、可理解的代码。
我个人认为> -1
更具可读性,但这可能非常主观。【参考方案9】:
我的猜测是它的存在是因为它短了几个字符(图书馆作者总是在追求)。它还使用编译成本机代码时只需要几个机器周期的操作(而不是与数字进行比较。)
我同意另一个答案,即这是一种矫枉过正的做法,但在紧密的循环中可能有意义(但需要估计性能增益,否则可能会过早优化。)
【讨论】:
【参考方案10】:jQuery.inArray()
为“未找到”返回 -1
,其补码 (~
) 为 0
。因此,~jQuery.inArray()
为“未找到”返回一个假值(0
),为“找到”返回一个真值(负整数)。 !!
然后将虚假/真实形式化为真正的布尔 false
/true
。因此,!!~jQuery.inArray()
将为“找到”提供 true
,为“未找到”提供 false
。
【讨论】:
【参考方案11】:~
运算符是按位 NOT 运算符。这意味着它需要一个二进制形式的数字,然后将所有零变为一,将一变为零。
例如,二进制中的数字 0 是 0000000
,而 -1 是 11111111
。同样,1 是二进制的00000001
,而-2 是11111110
。
【讨论】:
【参考方案12】:波浪号是按位非 - 它反转值的每一位。作为一般经验法则,如果你在一个数字上使用~
,它的符号将被反转,然后减 1。
因此,当您执行~0
时,您会得到-1(0 反转为-0,减1 为-1)。
它本质上是一种精细的、超微优化的方法,用于获取始终为布尔值的值。
【讨论】:
【参考方案13】:~
运算符是按位补码运算符。 inArray()
的整数结果要么是 -1(当未找到元素时),要么是某个非负整数。 -1 的按位补码(以二进制表示为所有 1 位)为零。任何非负整数的按位补码总是非零。
因此,当整数“i”是非负整数时,!!~i
将是 true
,而当“i”正好是 -1 时,false
。
注意~
总是将其操作数强制为整数;也就是说,它将非整数浮点值强制为整数,以及非数字值。
【讨论】:
以上是关于!!~(不是波浪号/bang bang 波浪号)如何改变“包含/包含”数组方法调用的结果?的主要内容,如果未能解决你的问题,请参考以下文章
~~(“双波浪号”)在 Javascript 中的作用是啥?