波浪号在表达式之前会做什么?


Answers:


266

~按位运算符,用于翻转其操作数中的所有位。

例如,如果您的数字为1,则其对IEEE 754浮点数(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()发现返回值放入truthy(同时使未找到falsy)人们通常会增加一倍它用它截断数字为32位(和丢弃其小数代替它的副作用,实际上与Math.floor()正数相同)。

我说不清楚,因为目前尚不清楚它的用途。通常,您希望您的代码与阅读它的其他人清楚地交流。尽管使用起来~可能看起来很酷,但出于自身利益考虑,通常太聪明了。:)

现在JavaScript具有Array.prototype.includes()和也不再相关String.prototype.includes()。这些返回布尔值。如果您的目标平台支持它,则应首选此方法来测试字符串或数组中是否存在值。


2
讨厌的话对吗?如果可行,我就称其为语言的成语。有很多成语。一旦您学习了它们,它们并不会不清楚。如果您不了解列表推导,则在Python中尚不清楚,并且可以通过更多详细的循环来实现,但您绝不会要求Python程序员不要使用它们。同样,value = value || default在JavaScript中,只要您知道何时可以使用和不使用它,它就是一个常见且有效的习惯用法。
gman 2014年

3
@gman我猜是否有人使用并不重要。我认为将列表理解(语言功能)与此进行比较并不是一回事(避免键入一些额外字符的聪明方法)。如果您认为讨厌这个词太苛刻,请随时修改我的答案。
亚历克斯

2
也许更常见的例子是v = t ? a : b;。我发现这比var v; if (t} { v = a; } else { v = b; }通常跨越5条以上的线清晰得多var v = b; if (t) { v = a; },也比通常跨越4条以上的线更清晰。但是我知道很多人不熟悉? :运营商,他们更喜欢第二或第三种方式。我发现第一个更具可读性。我同意一般原则,使代码清晰明了,不要使用hack。我想我一看~v.indexOf('...')就会很清楚。
gman 2014年

9
当您在一家拥有许多开发人员的大型公司中工作时,您需要清楚地编写(ENGLISH)代码并对其进行很好的记录。使用带有垃圾回收的语言进行高级编码的目的是避免考虑二进制操作,而且许多前端开发人员甚至都没有汇编语言的经验。
user2867288 '16

3
我不会叫~惯用的。从技术上讲,它是语言规范的一部分,但在通用语言,它并不是那么多。
worc

108

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

如果返回值为-1,则~-10因为-1是全1的字符串。任何大于或等于零的值都将得出非零的结果。从而,

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

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

当然,这也可以:

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

而且它的神秘性也大大降低了。

有时您还会看到以下内容:

var i = ~~something;

~像这样两次使用运算符是将字符串转换为32位整数的快速方法。第一个~执行转换,第二个~将位反转。当然,如果将运算符应用于无法转换为数字的对象,则会得到NaN结果。(编辑 -实际上~是首先应用的是第二个,但是您知道了。)


2
对于那些不想逐位求反的人,~当对整数执行等于时-(x + 1)
FABRICIO磨砂

好像,您知道,数值首先也应该返回负布尔值。但是,我猜JS中只有另一个失败了吗?
wwaawaw 2012年

7
@adlwalrus的0存在false与非零的传统true可以追溯到至少70年代的C语言以及可能存在的许多其他当时的系统编程语言。它可能源于硬件的工作方式。许多CPU在某个操作后将其设置为零,并具有相应的分支指令对其进行测试。
Pointy

4
将其转换为32位int的更快方法是| 0,在这种情况下,仅执行一次操作。
Alex

@alex确实可以,尽管我们不必一定相信运行时不会以~~完全相同的方式解释简单的应用程序。
尖尖的2015年

28

~按位NOT运算符~x是大致相同的-(x+1)。有点容易理解。所以:

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

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

换句话说,~与一定范围的数字值一起使用时,只会为输入值生成伪造(强制到falsefrom 0-1值,否则将生成任何其他真实值。

众所周知,-1通常称为哨兵值。它用于返回许多功能>= 0的值的成功-1失败的 C语言编写。indexOf()JavaScript 中返回值的规则相同。

通常用这种方法检查另一个字符串中是否存在子字符串

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
}

您不知道JS:类型和语法(Kyle Simpson)


1
这是肯定更容易在面值明白,即使一个人不明白,使得它的工作背景。-(x+1)如果在if语句中看到它,我将进行第二次查看。代字号准确地告诉我如何补偿Javascript基于0的本质。另外,括号越少越好阅读
普通Joe

在您最初的检查代码块中,您可以使用较少的if (a.indexOf("Ba") > -1) {// found} //true字符键入内容,尽管比波浪符示例更长,但比您给出的两个示例要少得多,对于新程序员来说是可以var opinion = !~-1 ? 'more' : 'less'理解的。
Hmerman6006

24

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

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

1
我同意。Airbnb JavaScript样式指南不受欢迎++--因为它们“鼓励过度的技巧”,但以某种方式~得以幸存(潜伏在阴影中)github.com/airbnb/javascript/issues/540
Shanimal

@Shanimal替代方法是list.indexOf(item) >= 0... > -1因为javascript是从零开始的,所以从一开始就没有选择解决此问题。此外,仅凭意见(与Airbnb相同),任何在javascript中做有意义的事情的人都知道++,尽管--不那么普遍,但可以推断出含义。
定期的乔

@RegularJoe我大部分都同意。我个人没有必要++--,因为像原始的方法了一会儿mapforEach等我的观点更多的是为什么他们也没考虑~过棘手的任何时候标准中使用包括增量和减量运算。禁止某些东西使CIS101没有任何意义。
Shanimal

11

对于那些考虑使用代字号技巧从结果中创建真实值的人来说indexOf,使用上的includes方法String更明确,并且魔术性也较小。

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

请注意,这是ES 2015的新标准方法,因此在旧版浏览器上将无法使用。如果这很重要,请考虑使用String.prototype.includes polyfill

此功能也可用于使用相同语法的数组:

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

如果需要较旧的浏览器支持,则为Array.prototype.includes polyfill


2
避免使用include()。在撰写本文时,任何版本的IE(不只是较旧的浏览器)均不支持它: developer.mozilla.org/en/docs/Web/JavaScript/Reference/...
Onshop

8
或者只是使用编译器,因此您可以编写更清晰的代码,而不用根据最糟糕的公分母JS解释器编写语言...
Kyle Baker

2
@Ben是正确的,它在Netscape 4.72中也不起作用。
mikemaccana
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.