是什么 !! (而不是)运营商的JavaScript?

我看到一些代码,似乎使用了一个我不认识的操作符,以两个感叹号的forms,就像这样: !! 。 有人能告诉我这个操作员做什么吗?

我看到这种情况是,

 this.vertical = vertical !== undefined ? !!vertical : this.vertical; 

强制oObject为布尔值。 如果它是假的(例如0, nullundefined等),则它将是false ,否则是true

 !oObject //Inverted boolean !!oObject //Non inverted boolean so true boolean representation 

所以!! 不是操作员,只是! 操作员两次。

真实世界范例“testingIE版本”:

 let isIE8 = false; isIE8 = !! navigator.userAgent.match(/MSIE 8.0/); console.log(isIE8); // returns true or false 

如果你=>

 console.log(navigator.userAgent.match(/MSIE 8.0/)); // returns null 

但如果你=>

 console.log(!!navigator.userAgent.match(/MSIE 8.0/)); // returns true or false 

做一个types转换是一个非常晦涩难懂的方法。

! 不是 。 所以!true false ,而!falsetrue!0true!1false

所以你将一个值转换为一个布尔值,然后反转,然后再次反转。

 // Maximum Obscurity: val.enabled = !!userId; // Partial Obscurity: val.enabled = (userId != 0) ? true : false; // And finally, much easier to understand: val.enabled = (userId != 0); 

!!expr根据expression式的真实性!!expr返回一个布尔值( truefalse )。 在非布尔types上使用它更有意义。 考虑这些例子,特别是第三个例子和以后的例子:

  !!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

  • 事实是, truefalse (这就是为什么!true结果是false


!! 决定了什么是价值的“真理”:

  • 事实是, true 并非 true (这就是为什么!!true结果是true

  • 事实是, false 不是 false (这就是为什么!!false结果是false


我们希望在比较中确定的是关于参考价值的“真相”,而不是参考本身的价值 。 有一个用例,我们可能想要知道关于值的真实性,即使我们期望值是false (或者假的),或者如果我们期望值不是typeof boolean


在实践中:

考虑一个简洁的函数,通过dynamictypes (又名“duck typing”)来检测特征function(在这种情况下,平台兼容性)。 我们希望编写一个函数,如果用户的浏览器支持HTML5 <audio>元素,则返回true ,但是如果<audio>未定义,我们不希望函数抛出错误。 我们不想用try ... catch来处理任何可能的错误(因为它们是粗略的)。 而且我们也不希望在函数内部使用一个检查来不断地揭示这个特性的真实性(例如, document.createElement('audio')仍然会创build一个名为<audio>的元素,即使HTML5 <audio>不支持)。


以下是三种方法:

 // this won't tell us anything about HTML5 `<audio>` 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 

每个函数接受一个<tag>和一个attribute来查找的参数,但是每个函数都会根据比较的结果返回不同的值。

但是等等,还有更多!

你们中的一些人可能注意到,在这个特定的例子中,可以简单地检查一个属性,使用稍微更高效的方式来检查所讨论的对象是否具有属性。 有两种方法可以做到这一点:

 // 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 

我们离题了

然而,这些情况很less见,可能存在一些情况,其中最简洁,最高性能,因此最优选的从非布尔值,可能未定义的值获得true值的方法确实是通过使用!! 。 希望这可笑地清除它。

!! 将其右侧的值转换为其等价的布尔值。 (认为​​穷人的“铸造”的方式)。 它的目的通常是向读者传达,代码不在乎variables中的值是什么,而是“真值”是什么。

!!foo应用一元非运算符两次,用于转换为布尔types,类似于使用一元加+foo转换为数字并连接空string''+foo以转换为string。

您也可以使用与原始types相对应的构造函数( 使用new )来明确地转换值,即

 Boolean(foo) === !!foo Number(foo) === +foo String(foo) === ''+foo 

它只是逻辑NOT运算符,两次 – 它用来将某些东西转换为布尔值,例如:

 true === !!10 false === !!0 

它将后缀转换为布尔值。

这么多答案做了一半的工作。 是的, !!X可以被理解为“X的真实性(用布尔表示)”。 但是!! 实际上,对于确定单个variables(或者甚至是多个variables)是真的还是假的是非常重要的。 !!myVar === truemyVar 。 将!!X比作一个“真正的”布尔值并不是很有用。

你得到什么!! 是以可重复的,标准化的(和JSLint友好的)方式来检查多个variables的真实性的能力。

简单地铸造:(

那是…

  • 0 === falsefalse
  • !!0 === falsetrue

以上没有那么有用。 if (!0)给出与if (!!0 === false)相同的结果。 我不能想到一个很好的情况下将一个variables转换为布尔值,然后比较一个“真正的”布尔值。

请参阅JSLint的指示 (注意:Crockford正在移动他的站点,这个链接有可能在某个时候死亡)的“==和!=”,为什么:

==和!=运算符在比较之前进行types强制转换。 这是不好的,因为它会导致'\ t \ r \ n'== 0为真。 这可以掩盖types错误。 JSLint不能可靠地确定==是否正确使用,所以最好不要使用==和!=而是总是使用更可靠的===和!==运算符。

如果你只关心某个值是真的还是虚假的,那就用简写的forms。 代替
(foo != 0)

说啊
(foo)

而不是
(foo == 0)


(!foo)

请注意,在比较布尔值和数字时,会有一些不直观的情况 ,其中一个布尔值将被转换为数字( true被强制转换为1false0 )。 在这种情况下!! 可能是精神上有用的。 尽pipe如此, 在这种情况下,您正在比较非布尔型和硬式布尔型,即imo,这是一个严重的错误。 if (-1)仍然是这里的路。

 ╔═══════════════════════════════════════╦═══════════════════╦═══════════╗ ║ 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,例如,赢得奖品。

 function test() { return (1 === 1); } WScript.echo(test()); 

由于一些历史性的Windows jive ,它会在消息框中输出-1! 尝试在cmd.exe提示符下看看! 但是WScript.echo(-1 == test())仍然给你0,或者WScript的false 。 看看。 这是可怕的。

比较真实:)

但是,如果我有两个价值,我需要检查相同的truthi / falsi-ness?

假装我们有myVar1 = 0;myVar2 = undefined;

  • myVar1 === myVar20 === undefined ,显然是错误的。
  • !!myVar1 === !!myVar2!!0 === !!undefined ,是真的! 同样的真诚! (在这种情况下,都是“有虚伪的真实”)。

所以你唯一需要使用“布尔型variables”的地方是,如果你有一种情况,你要检查两个variables是否有相同的真实性,对吗? 就是!! 如果你需要看看两个variables是真的还是两个都是虚假的 ,也就是说, 是否相同 (或不是) 真实

我想不出一个伟大的,没有人为的用例。 也许你有一个表格“链接”字段?

 if (!!customerInput.spouseName !== !!customerInput.spouseAge ) { errorObjects.spouse = "Please either enter a valid name AND age " + "for your spouse or leave all spouse fields blank."; } 

所以,现在如果你对配偶的姓名和年龄都有一个真相,那么你可以继续。 否则,你只有一个有价值的领域(或者是一个非常早期的婚姻),需要在你的errorObjects集合上创build一个额外的错误。


编辑2017年10月24日:

期望显式布尔值的第三方库

这是一个有趣的案例… !! 当第三方库期望显式的布尔值时可能会有用。

例如, JSX中的False(React)有一个特殊的含义 ,不是简单的谬误触发的。 如果您尝试在JSX中返回类似以下的内容,则需要在messageCount一个int …

{messageCount && <div>You have messages!</div>}

…当您有零消息时,您可能会惊讶地看到React渲染为0 。 您必须显式返回false才能呈现JSX。 上面的语句返回0 ,JSX愉快地呈现它,应该如此。 它不能告诉你没有Count: {messageCount && <div>Get your count to zero!</div>} (或更less的人为)。

  • 一个修复涉及到bangbang,强制0变成!!0 ,这是false
    {!!messageCount && <div>You have messages!</div>}

  • JSX的文档build议你更加明确,编写自我评论的代码,并使用比较强制布尔。
    {messageCount > 0 && <div>You have messages!</div>}

  • 我更喜欢用一个三元组来处理诡计 –
    {messageCount ? <div>You have messages!</div> : false}

请记住, 是一个JSX约定 ,并不是JavaScript固有的

但是如果你在渲染的JSX中看到奇怪的0那么请考虑松散的pipe理。

这是一个双重的not操作。 第一! 将该值转换为布尔值并将其逻辑值反转。 第二! 将逻辑值反转。

它模拟了Boolean()强制转换函数的行为。 第一个NOT不pipe返回一个布尔值,不pipe它给出了什么操作数。 第二个NOT否定了Boolean值,所以给出了一个variables的true布尔值。 最终结果与在Boolean()上使用Boolean()函数相同。

! 是“boolean not”,它基本上将“enable”的值强制转换为布尔值相反的值。 第二 ! 翻转这个值。 所以, !!enable意味着“不启用”,给你enable作为布尔值的值。

这似乎是!! 运算符导致双重否定。

 var foo = "Hello World!"; !foo // Result: false !!foo // Result: true 

我认为值得一提的是,一个与逻辑AND / OR相结合的条件不会返回一个布尔值,但最后的成功或者首先在&&的情况下失败,并且在||的情况下第一次成功或者最后失败。 的条件链。

 res = (1 && 2); // res is 2 res = (true && alert) // res is function alert() res = ('foo' || alert) // res is 'foo' 

为了将条件转换为真布尔文字,我们可以使用双重否定:

 res = !!(1 && 2); // res is true res = !!(true && alert) // res is true res = !!('foo' || alert) // res is true 

!! 构造是将任何JavaScriptexpression式转换为布尔等价的简单方法。

例如: !!"he shot me down" === true!!0 === false

这不是一个单一的运营商,而是两个。 它相当于以下内容,并且是将值转换为布尔值的快捷方式。

 val.enabled = !(!enable); 

这里有很多很好的答案,但是如果你已经读了这么多,这就帮助我“得到它”。 在Chrome(等)上打开控制台,然后开始input:

 !(!(1)) !(!(0)) !(!('truthy')) !(!(null)) !(!('')) !(!(undefined)) !(!(new Object()) !(!({})) woo = 'hoo' !(!(woo)) ...etc, etc, until the light goes on ;) 

当然,这些都与仅仅input!! someThing相同,但添加的括号可能会使其更容易理解。

ifwhile语句和? 运算符使用真值来确定运行哪个代码分支。 例如,零和NaN数字和空string是假的,但其他数字和string是真实的。 对象是真的,但未定义的值和null都是假的。

双重否定操作符!! 计算一个值的真值。 它实际上是两个运算符,其中!!x表示!(!x) ,其行为如下:

  • 如果x是一个假值,则!xtrue ,并且!!xfalse
  • 如果x是一个真值, !xfalse!!xtrue

当在布尔上下文的顶层使用( ifwhile? )时, !! 操作员在行为上是无操作的。 例如, if (x)if (!!x)意味着同样的事情。

实际用途

但它有几个实际用途。

一种用途是将对象损失压缩为其真值,以便您的代码不会持有对大对象的引用并保持活动状态。 将!!some_big_object给一个variables而不是some_big_object让我们把它some_big_object垃圾收集器中。 这对于产生一个对象或一个错误值(如null或未定义的值(如浏览器特征检测)的情况非常有用。

另一个用法,我在一个关于C的对应答案中提到!! 操作员使用“lint”工具查找常见的拼写错误和打印诊断。 例如,在C和JavaScript中,布尔操作的一些常见拼写错误会产生其他输出不如布尔型的行为:

  • if (a = b)是赋值,然后使用b的真值; if (a == b)是一个相等的比较。
  • if (a & b)是按位与; if (a && b)是一个逻辑与。 2 & 50 (一个错误的值); 2 && 5是真的。

!! 操作员再次确认你所写的lint工具是你的意思:做这个操作,然后拿出结果的真值。

第三个用途是产生逻辑XOR和逻辑XNOR。 在C和JavaScript中, a && b执行逻辑AND(如果双方均为true,则为true),而a & b执行按位AND。 a || b a || b执行逻辑OR(如果至less有一个为真,则为真)以及a | b a | b执行按位或。 有一个按位异或(异或)作为a ^ b ,但是没有内置的逻辑异或运算符(true,如果正好一边是真的)。 例如,您可能希望允许用户在两​​个字段中的一个中input文本。 你可以做的是将每一个转换成一个真值,并将它们进行比较: !!x !== !!y

双布尔否定。 经常用来检查值是不是未定义的。

我怀疑这是C ++中的一个剩余部分, 而不是布尔运算符。

所以在这种情况下,要得到否定的(或肯定的)答案,你首先需要使用! 运算符得到一个布尔值,但如果你想检查正面的情况下会使用!!

!!xBoolean(x)简写

第一次爆炸迫使js引擎运行Boolean(x)但也有反转值的副作用。 所以第二次爆炸解除了副作用。

这里是一个angularjs的代码片段

 var requestAnimationFrame = $window.requestAnimationFrame || $window.webkitRequestAnimationFrame || $window.mozRequestAnimationFrame; var rafSupported = !!requestAnimationFrame; 

他们的意图是根据requestAnimationFrame中函数的可用性将rafSupported设置为true或false

一般可以通过以下方式来实现:

 if(typeof requestAnimationFrame === 'function') rafSupported =true; else rafSupported =false; 

简短的方式可以使用!

 rafSupported = !!requestAnimationFrame ; 

所以如果requestAnimationFrame被分配了一个函数,那么!requestAnimationFrame将是错误的,还有一个! 这是真的

如果requestAnimationFrame的assinged undefined那么!requestAnimationFrame将是真实的,还有一个! 这将是错误的

JavaScript中的一些运算符执行隐式types转换,有时用于types转换。

一元! 运算符将其操作数转换为布尔值并将其取反。

这个事实导致了你可以在源代码中看到的以下习惯用法:

 !!x // Same as Boolean(x). Note double exclamation mark 

返回一个variables的布尔值。

相反,可以使用Boolean类。

(请阅读代码说明)

 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` 

Boolean(X) = !!X在使用中。

请检查下面的代码片段

 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("\n") // newline a = 1 console.log("a: ", a) console.log("!a: ", !a) console.log("!!a: ", !!a) // writes 1 value in boolean console.log("\n") // 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("\n") // 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 
 a = 1; alert(!a) // -> false : a is not not defined alert(!!a) // -> true : a is not not defined 

对于!a ,它检查a是否未定义,而!!a检查variables是否已定义。

!!a!(!a) 。 如果a被定义, atrue!afalse ,而且!!atrue

使用逻辑非运算符两次
这意味着!真=假
和!! true = true

!! 类似于使用布尔构造函数 ,或者更像是布尔函数。

 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( "\n---------------------" ) // 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 

I just wanted to add that

 if(variableThing){ // do something } 

是相同的

 if(!!variableThing){ // do something } 

But this can be an issue when something is undefined.

 // 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 

The trick here is the chain of && s will return the first falsey value it finds — and this can be fed to an if statement etc. So if b.foo is undefined, it will return undefined and skip the b.foo.bar statement, and we get no error.

The above return undefined but if you have an empty string, false, null, 0, undefined those values will return and soon as we encounter them in the chain — [] and {} are both truthy.

After seeing all these great answers, I would like to add another reason for using !! 。 Currenty I'm working in Angular 2-4 (TypeScript) and I want to return a boolean as false when my user is not authenticated. If he isn't authenticated, the token-string would be null or "" . I can do this by using the next block of code:

 public isAuthenticated(): boolean { return !!this.getToken(); } 

!! it's using NOT operation twice together, ! convert the value to a boolean and reverse it, here is a the simple example to see how !! 作品:

At first place you have:

 var zero = 0; 

Then you do !0 , it will be converted to boolean and be evaluated to true , because 0 is falsy , so you get the reversed value and converted to boolean, so it gets evaluated to true .

 !zero; //true 

but we don't want the reversed boolean version of the value, so we can reverse it again to get our result! That's why we use another !

Basically, !! make us sure, the value we get is boolean, not falsy, truthy or string etc…

So it's like using Boolean function in javascript, but easy and shorter way to convert a value to boolean:

 var zero = 0; !!zero; //false