【问题标题】:What does a tilde do when it precedes an expression?波浪号在表达式之前有什么作用?
【发布时间】:2012-08-31 05:58:19
【问题描述】:
var attr = ~'input,textarea'.indexOf( target.tagName.toLowerCase() )
           ? 'value'
           : 'innerHTML'

我在一个答案中看到过,以前从未见过。

什么意思?

【问题讨论】:

标签: javascript syntax bit-manipulation


【解决方案1】:

~ 是一个 bitwise operator,它翻转其操作数中的所有位。

例如,如果您的号码是 1,那么它的 IEEE 754 float(JavaScript 如何处理数字)的二进制表示将是...

0011 1111 1111 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000

所以~ 将其操作数转换为 32 位整数(JavaScript 中的位运算符会这样做)...

0000 0000 0000 0000 0000 0000 0000 0001

如果是负数,则存储为 2 的补码:反转所有位并加 1。

...然后翻转所有位...

1111 1111 1111 1111 1111 1111 1111 1110

那么它有什么用呢?什么时候可以使用它?

它有很多用途。如果你正在编写低级的东西,它很方便。如果您分析了您的应用程序并发现了瓶颈,则可以通过使用按位技巧(作为一个可能工具在一个更大的包中)来提高它的性能。

indexOf()found 返回值转换为 truthy 也是一个(通常)不清楚的技巧(同时使 not found as falsy)并且人们经常使用它来将数字截断为 32 位(并通过将其加倍来删除小数位,实际上与 Math.floor() 相同的正数)数)。

我说不清楚是因为它的用途不是很明显。通常,您希望您的代码与阅读它的其他人清晰地交流。虽然使用~ 可能看起来很酷,但它通常太聪明了。 :)

现在 JavaScript 有 Array.prototype.includes()String.prototype.includes() 也不再那么重要了。这些返回一个布尔值。如果您的目标平台支持它,您应该更喜欢它来测试字符串或数组中是否存在值。

【讨论】:

  • 讨厌这个词合适吗?如果它有效,我会称它为语言的成语。有很多成语。一旦你学会了它们,它们就不清楚了。如果你不知道列表推导式在 Python 中并不清楚,并且可以通过更详细的循环来完成,但你永远不会要求 Python 程序员不要使用它们。类似地,JavaScript 中的value = value || default 是一个常见且有效的习语,只要你知道什么时候可以使用,什么时候不可以使用。
  • @gman 我想是否有人使用它并不重要。我认为将列表理解(语言功能)与此进行比较并不是一回事(聪明 避免输入一些额外字符的方法)。如果您认为 nasty 这个词太苛刻,请随时编辑我的答案。
  • 也许更常见的例子是v = t ? a : b;。我发现这比var v; if (t} { v = a; } else { v = b; } 清晰得多,通常跨越 5 行以上,也比var v = b; if (t) { v = a; } 更清晰,var v = b; if (t) { v = a; } 通常是 4 行以上。但我知道很多人不熟悉? : 运算符,他们更喜欢第二种或第三种方式。我发现第一个更具可读性。我同意一般原则,使代码清晰,不要使用黑客。我想我只是看到~v.indexOf('...') 非常清楚,一旦我学会了它。
  • 当您在一家拥有许多开发人员的大公司工作时,您希望代码写得清晰(英文)并且有据可查。使用垃圾回收语言进行高级编码的目的是避免考虑二进制操作,许多前端开发人员甚至没有汇编语言经验。
  • 我不会打电话给~ 惯用语。从技术上讲,它是语言 spec 的一部分,但它并不是 一般使用的语言 的一部分。
【解决方案2】:

indexOf() 表达式之前使用它可以有效地为您提供真/假结果,而不是直接返回的数字索引。

如果返回值为-1,那么~-1就是0,因为-1是一个全为1的字符串。任何大于或等于零的值都将给出非零结果。因此,

if (~someString.indexOf(something)) {
}

将导致if 代码在“someString”中存在“something”时运行。如果您尝试将.indexOf() 直接用作布尔值,那么这将不起作用,因为有时它会返回零(当“某物”位于字符串的开头时)。

当然,这也有效:

if (someString.indexOf(something) >= 0) {
}

而且它没有那么神秘。

有时您还会看到:

var i = ~~something;

像这样使用~ 运算符两次是一种将字符串转换为32 位整数的快速方法。第一个~ 进行转换,第二个~ 将位翻转回来。当然,如果将运算符应用于无法转换为数字的内容,则结果是 NaN。 (edit——实际上是第二个~首先应用,但你明白了。)

【讨论】:

  • 对于那些不想逐位取反的人,~对整数执行时等于-(x + 1)
  • 看起来,嗯,你知道,NEGATIVE 数值首先也应该返回负布尔值。但我猜只是另一个 JS 失败了?
  • @adlwalrus 以及 0false 和非零是 true 的传统可以追溯到很久以前,至少可以追溯到 70 年代的 C 并且可能还有许多其他当时的当代系统编程语言。它可能源于硬件的工作方式;很多CPU在一个操作后会设置一个0位,并有相应的分支指令来测试它。
  • 将其转换为 32 位 int 的更快方法是 | 0,在这种情况下它只有一个操作。
  • @alex 确实如此,尽管我们不一定相信运行时不会以完全相同的方式解释 ~~ 的简单应用程序。
【解决方案3】:

~Bitwise NOT Operator~x-(x+1) 大致相同。它更容易理解,有点。所以:

~2;    // -(2+1) ==> -3

考虑-(x+1)-1 可以执行该操作以生成 0

换句话说,~ 与一系列数值一起使用只会为-1 输入值生成虚假(从0 强制转换为false)值,否则,任何其他真实值。

众所周知,-1 通常被称为哨兵值。它用于许多在 C 语言中返回 >= 0 值表示 成功-1 表示 失败 的函数。 JavaScript中indexOf()的返回值规则与此相同。

以这种方式检查另一个字符串中是否存在子字符串是很常见的

var a = "Hello Baby";

if (a.indexOf("Ba") >= 0) {
    // found it
}
if (a.indexOf("Ba") != -1) { 
    // found it
}

if (a.indexOf("aB") < 0) { 
    // not found
}
if (a.indexOf( "aB" ) == -1) { 
    // not found
}

但是,通过~ 更容易做到这一点,如下所示

var a = "Hello Baby";

~a.indexOf("Ba");         // -7   -> truthy
if (~a.indexOf("Ba")) {   // true
    // found it
}

~a.indexOf("aB");         // 0    -> falsy
!~a.indexOf("aB");        // true
if (!~a.indexOf( "aB" )) {  // true
    // not found
}

You Don't Know JS: Types & Grammar by Kyle Simpson

【讨论】:

  • 肯定从表面上看更容易理解,即使一个人不了解使它起作用的背景。如果我在 if 语句中看到-(x+1),我会再看一遍。波浪号确切地告诉我它正在做什么来补偿 Javascript 的基于 0 的性质。 另外,括号越少阅读效果越好
  • 在您的初始检查代码块中,您可以使用if (a.indexOf("Ba") &gt; -1) {// found} //true 键入更少的内容,虽然比波浪号示例有点长,但比您提供的两个示例要少得多,对于新程序员var opinion = !~-1 ? 'more' : 'less'可以理解。
【解决方案4】:

~indexOf(item) 经常出现,这里的答案很好,但也许有些人只需要知道如何使用它并“跳过”理论:

   if (~list.indexOf(item)) {
     // item in list
   } else {
     // item *not* in list
   }

【讨论】:

  • 我同意。 Airbnb JavaScript 样式指南不允许 ++--,因为它们“鼓励过度狡猾”,但不知何故 ~ 幸存下来(潜伏在阴影中)github.com/airbnb/javascript/issues/540
  • @Shanimal 另一种选择是list.indexOf(item) &gt;= 0... &gt; -1,因为javascript 是从零开始的,并且从一开始就没有选择解决这个问题。此外,只是意见(与 Airbnb 的相同),任何在 javascript 中做任何有意义的事情的人都知道++,虽然-- 不太常见,但可以推断其含义。
  • @RegularJoe 我同意其中的大部分内容。由于mapforEach 等原始方法,我个人暂时不需要++--。我的观点更多的是关于为什么他们不考虑~ 在任何标准时都过于棘手used 包括递增和递减运算符。禁止某些事情,因此 CIS101 没有任何意义。
【解决方案5】:

对于那些考虑使用波浪号技巧从 indexOf 结果中创建 truthy 值的人来说,使用 includes method on String 来代替它更明确且魔力更小。

'hello world'.includes('hello') //=> true
'hello world'.includes('kittens') //=> false

请注意,这是 ES 2015 的新标准方法,因此它不适用于旧版浏览器。在重要的情况下,请考虑使用String.prototype.includes polyfill

此功能也可用于使用same syntax 的数组:

['apples', 'oranges', 'cherries'].includes('apples') //=> true
['apples', 'oranges', 'cherries'].includes('unicorns') //=> false

如果您需要旧版浏览器支持,这里是Array.prototype.includes polyfill

【讨论】:

  • 避免使用包含()。在撰写本文时,任何版本的 IE(不仅仅是旧浏览器)都不支持它:developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
  • 或者只用编译器,这样你就可以写出更清晰的代码,而不是按照最糟糕的公分母JS解释器来写语言......
  • @Ben 是对的,它在 Netscape 4.72 中也不起作用。
猜你喜欢
  • 2016-03-27
  • 2014-05-20
  • 2011-04-26
  • 1970-01-01
  • 2017-01-24
  • 2019-05-03
  • 2010-11-26
  • 2014-02-22
  • 2012-06-22
相关资源
最近更新 更多