波浪号在表达式之前有什么作用?

IT技术 javascript syntax bit-manipulation
2021-01-24 03:26:41
var attr = ~'input,textarea'.indexOf( target.tagName.toLowerCase() )
           ? 'value'
           : 'innerHTML'

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

这是什么意思?

5个回答

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

例如,如果您的数字是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

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

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

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

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

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

@gman 我想是否有人使用它并不重要。我认为将列表推导式(语言功能)与此进行比较并不是一回事(避免输入一些额外字符的巧妙方法)。如果您认为“讨厌”这个词太苛刻,请随时编辑我的答案。
2021-03-12 03:26:41
也许更常见的例子是v = t ? a : b;. 我发现这比var v; if (t} { v = a; } else { v = b; }通常跨越 5+ 行的更清晰,也比var v = b; if (t) { v = a; }通常 4+ 行的更清晰但我知道很多不熟悉? :运营商的人更喜欢第二种或第三种方式。我发现第一个更具可读性。我同意一般原则,让代码清晰,不要使用黑客。我想~v.indexOf('...')一旦我学会了,我就会看得很清楚。
2021-03-18 03:26:41
当您在拥有许多开发人员的大公司工作时,您希望代码编写清晰(英文)并有据可查。使用垃圾收集语言进行高级编码的重点是避免考虑二进制操作,许多前端开发人员甚至没有汇编语言经验。
2021-03-29 03:26:41
讨厌是正确的词吗?如果它有效,我会称它为该语言的习语。有很多成语。一旦你学会了它们,它们就不会不清楚。列表推导式在 Python 中不清楚,如果您不了解它们,并且可以通过更冗长的循环来完成,但您永远不会要求 Python 程序员不要使用它们。同样,value = value || default在 JavaScript 中,只要您知道何时可以使用和不可以使用它,它就是一个常见且有效的习语。
2021-03-31 03:26:41
我不会称之为~惯用语。从技术上讲,它是语言规范的一部分,但它并不是一般使用语言的重要部分
2021-04-09 03:26:41

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

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

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

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

当然,这也有效:

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

而且它的神秘性要低得多。

有时你还会看到这个:

var i = ~~something;

~像这样使用运算符两次是将字符串转换为 32 位整数的快速方法。第一个~进行转换,第二个~将位翻转回来。当然,如果运算符应用于无法转换为数字的内容,您就会得到NaN结果。编辑- 实际上它~是第一个应用的第二个,但你明白了。)

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

~按位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

在您最初的检查代码块中,您可以通过使用if (a.indexOf("Ba") > -1) {// found} //truewhich来减少输入,虽然比波浪号示例长一点,但比您提供的两个示例要少得多,并且对于新程序员来说是可以var opinion = !~-1 ? 'more' : 'less'理解的。
2021-03-20 03:26:41
表面上看肯定更容易理解,即使一个人不了解使其起作用的背景。-(x+1)如果我在 if 语句中看到它,我会再看一遍。波浪号准确地告诉我它正在做什么来补偿 Javascript 的基于 0 的特性。此外,括号越少阅读效果越好
2021-04-06 03:26:41

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

   if (~list.indexOf(item)) {
     // item in list
   } else {
     // item *not* in list
   }
@Sanimal 替代方案是list.indexOf(item) >= 0或者... > -1因为 javascript 是从零开始的,并且从一开始就没有选择解决这个问题。此外,只是意见(与 Airbnb 的相同),任何在 javascript 中做任何有意义的事情的人都知道++,虽然--不太常见,但可以推断其含义。
2021-03-28 03:26:41
我同意。Airbnb JavaScript 风格指南不允许++--因为它们“鼓励过度狡猾”,但不知何故~幸存下来(潜伏在阴影中)github.com/airbnb/javascript/issues/540
2021-04-04 03:26:41
@RegularJoe 我同意其中的大部分。我个人在一段时间内不需要++--因为像map,forEach原始方法。我的观点更多是关于为什么~当使用的任何标准包括增量和减量运算符时,他们也不会考虑过度棘手。禁止某些东西,因此 CIS101 没有任何意义。
2021-04-07 03:26:41

对于那些考虑使用波浪号技巧结果中创建值的人来说indexOf,使用includeson 上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

@Ben 是对的,它也不适用于 Netscape 4.72。
2021-03-13 03:26:41
或者只是使用编译器,这样你就可以编写更清晰的代码,而不是根据最糟糕的共同点 JS 解释器编写语言......
2021-04-03 03:26:41
避免使用includes()。在撰写本文时,任何版本的 IE(不仅仅是旧浏览器)都不支持它: developer.mozilla.org/en/docs/Web/JavaScript/Reference/...
2021-04-07 03:26:41