What is the !! (not not) operator in JavaScript?
我看到一些代码似乎使用了一个我不认识的运算符,形式是两个感叹号,就像这样:
我看到的背景是,
1 | this.vertical = vertical !== undefined ? !!vertical : this.vertical; |
强制
1 2 | !oObject //Inverted boolean !!oObject //Non inverted boolean so true boolean representation |
所以
现实世界中的"测试IE版本"示例:
1 2 3 | let isIE8 = false; isIE8 = !! navigator.userAgent.match(/MSIE 8.0/); console.log(isIE8); // returns true or false |
如果你?
1 2 | console.log(navigator.userAgent.match(/MSIE 8.0/)); // returns either an Array or null |
但是如果你?
1 2 | console.log(!!navigator.userAgent.match(/MSIE 8.0/)); // returns either true or false |
这是一种非常晦涩的类型转换方法。
所以你要把一个值转换成一个布尔值,然后反转它,然后再反转它。
1 2 3 4 5 6 7 8 | // Maximum Obscurity: val.enabled = !!userId; // Partial Obscurity: val.enabled = (userId != 0) ? true : false; // And finally, much easier to understand: val.enabled = (userId != 0); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | !!false === false !!true === true !!0 === false !!parseInt("foo") === false // NaN is falsy !!1 === true !!-1 === true // -1 is truthy !!"" === false // empty string is falsy !!"foo" === true // non-empty string is truthy !!"false" === true // ...even if it contains a falsy value !!window.foo === false // undefined is falsy !!null === false // null is falsy !!{} === true // an (empty) object is truthy !![] === true // an (empty) array is truthy; PHP programmers beware! |
沏茶:
理论上:
事实是,
false 不是true (这就是!false 结果的原因在true 中)事实是,
true 不是false (这就是!true 结果的原因在false 中)
事实上,
true 不是true (这就是!!true 导致true 的原因)事实上,
false 不是false (这就是!!false 导致false 的原因)
我们希望在比较中确定的是关于参考值的"真相",而不是参考值本身的价值。在一个用例中,我们可能想知道一个值的真实性,即使我们期望该值是
在实践中:
考虑一个简洁的函数,它通过动态类型(也称为"duck-typing")来检测特性功能(在本例中是平台兼容性)。如果用户的浏览器支持html5
以下是三种方法:
1 2 3 4 5 6 7 8 9 10 11 12 | // this won't tell us anything about HTML5 `` as a feature var foo = function(tag, atr) { return document.createElement(tag)[atr]; } // this won't return true if the feature is detected (although it works just fine) var bar = function(tag, atr) { return !document.createElement(tag)[atr]; } // this is the concise, feature-detecting solution we want var baz = function(tag, atr) { return !!document.createElement(tag)[atr]; } foo('audio', 'preload'); // returns"auto" bar('audio', 'preload'); // returns false baz('audio', 'preload'); // returns true |
每个函数接受
但是等等,还有更多!
有些人可能会注意到,在这个特定的示例中,可以使用稍微更高性能的方法检查一个属性,以检查相关对象是否具有属性。有两种方法可以做到这一点:
1 2 3 4 5 6 7 8 | // the native `hasOwnProperty` method var qux = function(tag, atr) { return document.createElement(tag).hasOwnProperty(atr); } // the `in` operator var quux = function(tag, atr) { return atr in document.createElement(tag); } qux('audio', 'preload'); // returns true quux('audio', 'preload'); // returns true |
我们离题了…
无论这些情况多么罕见,可能存在一些场景,其中最简洁、最具性能,因此,从非布尔值(可能是未定义的值)获取
除了这些黑客,您还可以使用与基元类型相对应的构造函数函数(不使用
1 2 3 | Boolean(foo) === !!foo Number(foo) === +foo String(foo) === ''+foo |
有那么多答案做了一半的工作。是的,
使用EDOCX1[1]所获得的好处是能够以可重复、标准化(和jslint友好)的方式检查多个变量之间的真实性。好的。简单铸造:(
那是…好的。
0 === false 为false 。!!0 === false 为true 。
上面没有那么有用。
看"="和"!"="从JSlint的方向(注意:Crockford正在移动他的站点一点;该链接在某个点上可能会死掉)了解一点原因:好的。
The == and != operators do type coercion before comparing. This is bad because it causes ' \t
' == 0 to be true. This can mask type errors. JSLint cannot reliably determine if == is being used correctly, so it is best to not use == and != at all and to always use the more reliable === and !== operators instead.
Ok.
If you only care that a value is truthy or falsy, then use the short form. Instead of
(foo != 0) Ok.
just say
(foo) Ok.
and instead of
(foo == 0) Ok.
say
(!foo) Ok.
请注意,有些非故意的情况下,当将布尔值与数字进行比较时,会将布尔值强制转换为数字(
1 2 3 4 5 6 7 8 9 10 11 12 | ╔═══════════════════════════════════════╦═══════════════════╦═══════════╗ ║ Original ║ Equivalent ║ Result ║ ╠═══════════════════════════════════════╬═══════════════════╬═══════════╣ ║ if (-1 == true) console.log("spam") ║ if (-1 == 1) ║ undefined ║ ║ if (-1 == false) console.log("spam") ║ if (-1 == 0) ║ undefined ║ ║ Order doesn't matter... ║ ║ ║ ║ if (true == -1) console.log("spam") ║ if (1 == -1) ║ undefined ║ ╠═══════════════════════════════════════╬═══════════════════╬═══════════╣ ║ if (!!-1 == true) console.log("spam") ║ if (true == true) ║ spam ║ better ╠═══════════════════════════════════════╬═══════════════════╬═══════════╣ ║ if (-1) console.log("spam") ║ if (truthy) ║ spam ║ still best ╚═══════════════════════════════════════╩═══════════════════╩═══════════╝ |
而且事情会变得更加疯狂,这取决于你的引擎。例如,Wscript赢得了奖品。好的。
1 2 3 4 5 | function test() { return (1 === 1); } WScript.echo(test()); |
由于某些历史Windows Jive,将在消息框中输出-1!在cmd.exe提示下尝试,然后查看!但是
但是,如果我有两个值,我需要检查是否具有相等的真实性/虚假性呢?好的。
假设我们有
myVar1 === myVar2 是0 === undefined ,显然是假的。!!myVar1 === !!myVar2 是!!0 === !!undefined 是真的!同样的真实!(在这种情况下,两人都"有一种虚伪的真实性"。)
所以,唯一真正需要使用"布尔值转换变量"的地方是,如果你有一种情况,你要检查两个变量是否具有相同的真实性,对吗?也就是说,如果需要查看两个变量是否都是真实的,或者都是错误的(或者不是),那就使用
我不能马上想到一个伟大的,非人为的用例。也许您在表单中有"链接"字段?好的。
1 2 3 4 | if (!!customerInput.spouseName !== !!customerInput.spouseAge ) { errorObjects.spouse ="Please either enter a valid name AND age" +"for your spouse or leave all spouse fields blank."; } |
所以现在,如果你对配偶的名字和年龄都有一个正确的答案,或是一个错误的答案,你可以继续。否则,您只有一个字段具有值(或非常早安排的婚姻),需要在您的
编辑:2017年10月24日,2月19日:好的。需要显式布尔值的第三方库
这是一个有趣的案例…当第三方libs期望显式的布尔值时,
例如,JSX中的false(react)有一个特殊的含义,它不是由简单的伪造触发的。如果您试图在JSX中返回类似以下内容的内容,希望在
…当您没有消息时,您可能会惊讶地看到react呈现一个
其中一个解决方案是邦邦,它将
0 强制为!!0 ,即false :{!!messageCount && You have messages!} 好的。JSX的文档建议您更加明确,编写自评代码,并使用比较强制使用布尔值。
{messageCount > 0 && You have messages!} 好的。我更愿意自己用三元数来处理错误。--
{messageCount ? You have messages! : false} 好的。
typescript中的处理方法相同:如果您有一个返回布尔值的函数(或者您正在为布尔变量赋值),则[通常]不能返回/赋值布尔-Y值;它必须是强类型布尔值。这意味着,如果
The exception for Typescript? If
myObject was anany , you're back in JavaScript's Wild West and can return it without!! , even if your return type is a boolean.Ok.
请记住,这些是JSX&typescript约定,而不是JavaScript固有的约定。好的。
但是,如果您在呈现的JSX中看到奇怪的
这只是逻辑非运算符,两次-它用于将某些内容转换为布尔值,例如:
1 2 3 | true === !!10 false === !!0 |
它将后缀转换为布尔值。
这是一个双
它模拟了
似乎
1 2 3 4 | var foo ="Hello World!"; !foo // Result: false !!foo // Result: true |
!是"boolean not",它本质上把"enable"的值类型转换为它的布尔值。第二!翻转此值。因此,
我认为值得一提的是,与逻辑和/或组合在一起的条件不会返回布尔值,但在&;&;和条件链的第一次成功或最后一次失败。
1 2 3 | res = (1 && 2); // res is 2 res = (true && alert) // res is function alert() res = ('foo' || alert) // res is 'foo' |
为了将条件强制转换为真正的布尔文字,我们可以使用双重否定:
1 2 3 | res = !!(1 && 2); // res is true res = !!(true && alert) // res is true res = !!('foo' || alert) // res is true |
例如:
不是一个接线员,是两个。它等价于以下内容,是将值强制转换为布尔值的快速方法。
1 | val.enabled = !(!enable); |
首先,你所在的地方:
1 | var zero = 0; |
然后你做
1 | !zero; //true |
但我们不希望该值的布尔值反转,所以我们可以再次反转该值以获得结果!这就是我们使用另一个
基本上,
因此,就像在javascript中使用
1 2 | var zero = 0; !!zero; //false |
我怀疑这是一个C++的残留物,人们在上面覆盖它!但不是布尔运算符。
因此,要得到否定(或肯定)的答案,在这种情况下,您首先需要使用!运算符得到一个布尔值,但如果要检查正的情况,将使用!!
双负算子
- 如果
x 为假值,!x 为true ,!!x 为false 。 - 如果
x 为真值,!x 为false ,!!x 为true 。
当在布尔上下文(
然而,它有几个实际用途。
一种用法是将对象无损压缩为其真值,这样代码就不会保存对大对象的引用并使其保持活动状态。把
另一种用法是使用"lint"工具查找常见的打字错误和打印诊断,我在关于C的对应
if (a = b) 是赋值后使用b 的真值;if (a == b) 是相等比较。if (a & b) 是位AND;if (a && b) 是逻辑AND。2 & 5 为0 (虚值);2 && 5 为真。
第三种用法是生成逻辑XOR和逻辑XNOR。在c和javascript中,
双重布尔否定。通常用于检查值是否未定义。
这里有很多很好的答案,但如果你读到这里,这帮助我"得到它"。打开Chrome(等)上的控制台,然后开始键入:
1 2 3 4 5 6 7 8 9 10 11 | !(!(1)) !(!(0)) !(!('truthy')) !(!(null)) !(!('')) !(!(undefined)) !(!(new Object()) !(!({})) woo = 'hoo' !(!(woo)) ...etc, etc, until the light goes on ;) |
当然,这些都和仅仅打字一样!!一些,但添加的括号可能有助于使其更易于理解。
第一次爆炸迫使JS引擎运行
它强制所有事物都是布尔型的。
例如:
1 2 3 4 5 6 7 8 9 10 11 | console.log(undefined); // -> undefined console.log(!undefined); // -> true console.log(!!undefined); // -> false console.log('abc'); // -> abc console.log(!'abc'); // -> false console.log(!!'abc'); // -> true console.log(0 === false); // -> undefined console.log(!0 === false); // -> false console.log(!!0 === false); // -> true |
这是Angular JS的一段代码
1 2 3 4 5 | var requestAnimationFrame = $window.requestAnimationFrame || $window.webkitRequestAnimationFrame || $window.mozRequestAnimationFrame; var rafSupported = !!requestAnimationFrame; |
他们的目的是根据requestAnimationFrame中函数的可用性将rafsupported设置为true或false。
一般可通过以下方式进行检查:
1 2 3 4 | if(typeof requestAnimationFrame === 'function') rafSupported =true; else rafSupported =false; |
这条捷径可能会用到!!
1 | rafSupported = !!requestAnimationFrame ; |
因此,如果RequestAnimationFrame被分配了一个函数然后!requestAnimationFrame将为false,并且还有一个!是真的。
如果未定义RequestAnimationFrame,则!RequestAnimationFrame将是真的,而且还有一个!那是假的
javascript中的一些运算符执行隐式类型转换,有时用于类型转换。
一元
这一事实导致了您可以在源代码中看到以下习惯用法:
1 | !!x // Same as Boolean(x). Note double exclamation mark |
我只是想补充一下
1 2 3 | if(variableThing){ // do something } |
是一样的
1 2 3 | if(!!variableThing){ // do something } |
但这可能是一个未定义的问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | // a is undefined, b is empty object. var a, b = {}; // Both of these give error a.foo is not defined etc. // you'd see the same behavior for !!a.foo and !!b.foo.bar a.foo b.foo.bar // This works -- these return undefined a && a.foo b.foo && b.foo.bar b && b.foo && b.foo.bar |
这里的诀窍是
上面的返回未定义,但是如果您有一个空字符串,那么,false、null、0、undefined,这些值将返回,并且一旦我们在链中遇到它们——
在看到这些伟大的答案之后,我想补充一下使用
1 2 3 | public isAuthenticated(): boolean { return !!this.getToken(); } |
返回变量的布尔值。
相反,可以使用
(请阅读代码说明)
1 2 3 4 | var X ="test"; // X value is"test" as a String value var booleanX = !!X // booleanX is `true` as a Boolean value beacuse non-empty strings evaluates as `true` in boolean var whatIsXValueInBoolean = Boolean(X) // whatIsXValueInBoolean is `true` again console.log(Boolean(X) === !!X) // writes `true` |
即使用中的
请检查下面的代码段↓
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | let a = 0 console.log("a:", a) // writes a value in its kind console.log("!a:", !a) // writes '0 is NOT true in boolean' value as boolean - So that's true.In boolean 0 means false and 1 means true. console.log("!!a:", !!a) // writes 0 value in boolean. 0 means false. console.log("Boolean(a):", Boolean(a)) // equals to `!!a` console.log(" ") // newline a = 1 console.log("a:", a) console.log("!a:", !a) console.log("!!a:", !!a) // writes 1 value in boolean console.log(" ") // newline a ="" console.log("a:", a) console.log("!a:", !a) // writes '"" is NOT true in boolean' value as boolean - So that's true.In boolean empty strings, null and undefined values mean false and if there is a string it means true. console.log("!!a:", !!a) // writes"" value in boolean console.log(" ") // newline a ="test" console.log("a:", a) // writes a value in its kind console.log("!a:", !a) console.log("!!a:", !!a) // writes"test" value in boolean console.log("Boolean(a) === !!a:", Boolean(a) === !!a) // writes true |
两次使用逻辑非运算符它的意思是!真=假而且!真=真
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | console.log(Boolean(null)); // Preffered over the Boolean object console.log(new Boolean(null).valueOf()); // Not recommended for coverting non-boolean values console.log(!!null); // A hacky way to omit calling the Boolean function, but essentially does the same thing. // The context you saw earlier (your example) var vertical; function Example(vertical) { this.vertical = vertical !== undefined ? !!vertical : this.vertical; // Let's break it down: If vertical is strictly not undefined, return the boolean value of vertical and set it to this.vertical. If not, don't set a value for this.vertical (just ignore it and set it back to what it was before; in this case, nothing). return this.vertical; } console.log(" ---------------------" ) // vertical is currently undefined console.log(new Example(vertical).vertical); // The falsey or truthy value of this.vertical console.log(!!new Example(vertical).vertical); // Coerced value of this.vertical vertical = 12.5; // set vertical to 12.5, a truthy value. console.log(new Example(vertical).vertical); // The falsey or truthy value of this.vertical which happens to be true anyway console.log(!!new Example(vertical).vertical); // Coerced value of this.vertical vertical = -0; // set vertical to -0, a falsey value. console.log(new Example(vertical).vertical); // The falsey or truthy value of this.vertical which happens to be false either way console.log(!!new Example(vertical).vertical); // Coerced value of this.vertical |
javascript中的假值强制为假,而truthy值强制为真。假值和真值也可用于
Although this may seem similar to casting, realistically this is likely a mere coincidence and is not 'built' or purposely made for and like a boolean cast. So let's not call it that.
为什么以及如何工作
简而言之,它看起来是这样的:
< BR>
回到你的例子总的来说,您看到的上下文根据是否定义了
< BR>
垂直I/O示例运行这个例子,并在输入中摆弄垂直值。查看结果强制执行的内容,以便您能够完全理解上下文的代码。在输入中,输入任何有效的javascript值。如果要测试字符串,请记住包括引号。不要太在意CSS和HTML代码,只需运行这段代码片段并使用它。但是,您可能希望了解与DOM无关的JavaScript代码(使用示例构造函数和垂直变量)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | var vertical = document.getElementById("vertical"); var p = document.getElementById("result"); function Example(vertical) { this.vertical = vertical !== undefined ? !!vertical : this.vertical; return this.vertical; } document.getElementById("run").onclick = function() { p.innerHTML = !!( new Example(eval(vertical.value)).vertical ); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | input { text-align: center; width: 5em; } button { margin: 15.5px; width: 14em; height: 3.4em; color: blue; } var { color: purple; } p { margin: 15px; } span.comment { color: brown; } |
1 2 3 4 5 6 7 | <!--Vertical I/O Example--> <h4>Vertical Example</h4> <code id="code"><var class="var">var</var> vertical = <input type="text" id="vertical" maxlength="9" />; <span class="comment">// enter any valid javascript value</span></wyn> <br /> <button id="run">Run</button> <p id="result">... </p> |
1 2 3 | a = 1; alert(!a) // -> false : a is not not defined alert(!!a) // -> true : a is not not defined |
对于
这个问题已经回答得很彻底了,但我想补充一个我希望尽可能简化的答案,使其意义!!尽可能简单地掌握。
因为javascript具有所谓的"真实"和"虚假"值,所以有些表达式在其他表达式中进行计算时,会导致出现真实或虚假条件,即使所检查的值或表达式实际上不是
例如:
1 2 3 | if (document.getElementById('myElement')) { // code block } |
如果该元素确实存在,则表达式的值将为true,并将执行代码块。
然而:
1 2 3 | if (document.getElementById('myElement') == true) { // code block } |
…不会产生真实的条件,即使元素确实存在,也不会执行代码块。
为什么?因为
在这种情况下,两个"not"非常简单。它只是两个
第一个简单地"反转"真实或虚假的值,从而产生实际的布尔类型,然后第二个简单地"反转"它再次回到它的原始状态,但现在是实际的布尔值。这样你就有了一致性:
1 | if (!!document.getElementById('myElement')) {} |
和
1 | if (!!document.getElementById('myElement') == true) {} |
两者都将按预期返回true。
双倍!将变量计算为其布尔值。Eg:假0(零)、""或""(空字符串)、空、未定义、NaN的计算结果为假。请参阅本帖https://www.sitepoint.com/javascript-truthy-falsy/
有时有必要检查我们在函数中是否有一个值,这个值本身对我们来说并不重要,但它是否重要。例如,我们想要检查,如果用户有或没有专业,并且我们有一个类似的函数:
1 | hasMajor(){return this.major}//it return"(users major is)Science" |
但答案对我们来说并不重要,我们只想检查它是否有主变量,我们需要一个布尔值(真或假),如何得到它:
就像这样:
1 | hasMajor(){ return !(!this.major)} |
还是一样
1 | hasMajor(){return !!this.major)} |
如果this.major有一个值,那么
这是一种检查未定义"未定义"、空值"空值"、"未定义"的非常方便的方法。
1 2 3 | if (!!var1 && !!var2 && !!var3 && !!var4 ){ //... some code here } |