提问



我看到一些似乎使用操作符的代码,我不会以两个感叹号的形式识别出来,如此:!!。有人可以告诉我这个操作符的作用吗?


我看到这个的背景是,


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

最佳参考


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


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


所以!!不是运算符,只是!运算符两次。


真实世界示例测试IE版本:


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

其它参考1


进行类型转换是一种非常模糊的方式。


!是 NOT 。所以!truefalse!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);

其它参考2


!!expr返回一个布尔值(truefalse),具体取决于表达式的真实性。在非布尔类型上使用时更有意义。考虑这些示例,尤其是第3个示例及以后的示例:


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

其它参考3


喝点茶:


!!不是运营商。它是!的两用 - 这是逻辑非运算符。





理论上:


! 决定了价值不是什么的真相:



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

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






!! 确定不的值的真相:



  • 事实是true不是不 true(这就是为什么!!true导致 true )

  • 事实是false不是不 false(这就是为什么!!false导致 false )






我们希望在比较中确定的是真相关于引用的值,而不是引用本身的值。有一个用例我们可能想知道一个值的真相,即使我们期望值为 false (或falsey),或者我们期望值不是是boolean的类型。





在实践中:


考虑一个简洁的功能,通过动态类型(又名鸭子打字)检测功能功能(在这种情况下,平台兼容性)。如果用户的浏览器支持HTML5 <audio>元素,我们想编写一个返回true的函数,但如果<audio>未定义,我们不希望函数抛出错误;我们不想使用try ... catch来处理任何可能的错误(因为它们很粗糙); 以及我们不想在函数内部使用检查,因为它不能始终如一地揭示该特征的真相(例如,document.createElement('audio')仍会创建一个名为<audio>的元素]]即使不支持HTML5 <audio>[234]





以下是三种方法:


// 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的参数来查找,但它们每个都根据比较确定的值返回不同的值。


但等等,还有更多!


你们中的一些人可能已经注意到,在这个具体的例子中,人们可以使用稍微更高性能的方法检查属性,以检查相关对象是否具有属性。有两种方法可以做到这一点:[235]


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


我们离题......


无论这些情况多么罕见,可能存在一些场景,其中最简洁,最高效,最优选的方法是从非布尔值,可能未定义的值获得true确实是通过使用!!]]。希望这可笑地清除它。

其它参考4


!!将其右侧的值转换为其等效的布尔值。 (想想穷人的打字方式)。它的意图通常是向读者传达代码并不关心变量中的值是什么但是它的真理价值是什么。[236]

其它参考5


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


您也可以使用与基元类型相对应的构造函数(不使用使用new)来显式转换值,而不是这些黑客,即


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

其它参考6


这么多答案做了一半的工作。是的,!!X可以被解读为X的真实性[[表示为布尔]]。但!!实际上并非如此重要,以确定单个变量是否(或者即使许多变量是真实的)还是虚假的。!!myVar === truemyVar相同将!!X与真实布尔值进行比较并不是很有用。


!!获得的是能够以可重复,标准化(和JSLint友好)的方式检查多个变量相互之间的真实性。


简单地施放:(



那是...



  • 0 === falsefalse

  • !!0 === falsetrue



上面的不太有用。if (!0)给你的结果与if (!!0 === false)相同。我不能想到将变量转换为布尔值然后比较真布尔值的好例子。


请参阅JSLint指示中的==和!=(注意:Crockford正在移动他的网站一点点;这个链接可能会在某些时候死亡),原因如下:[237]



  ==和!=运算符在比较之前键入强制。这很糟糕,因为它会导致\\ t \\ r \\ n== 0为真。这可以掩盖类型错误。 JSLint无法可靠地确定是否正确使用==,因此最好不要使用==和!=并始终使用更可靠的===和!==运算符。

  
  如果您只关心某个值是真或假,那么请使用简短形式。而不是

  (foo != 0)

  
  只是说

  (foo)

  
  而不是

  (foo == 0)

  
  说结果
  (!foo)



请注意,在将布尔值与数字进行比较时,会出现一些不直观的情况,其中布尔值将转换为数字(true转换为1false转换为0) 。在这种情况下,!!可能在精神上有用。虽然,再次,这些情况下你将非布尔值与硬类型布尔值进行比较,即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,ll在消息框中输出-1!在cmd.exe提示符下尝试看看!但是WScript.echo(-1 == test())仍然给你0或WScript的false。把目光移开这很可怕。 [240]


比较真实性:)



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


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



  • myVar1 === myVar20 === undefined,显然是假的。

  • !!myVar1 === !!myVar2!!0 === !!undefined并且是真的!同样诚实! (在这种情况下,两者都有真实性。)



因此,你真正需要使用boolean-cast变量的唯一地方就是如果你有一种情况,你要检查两个变量是否都具有相同的真实性,对吧?也就是说,使用!!如果您需要查看两个变量是是真的还是两个虚假(或不是),即等于 (或不)真实性。


我不能想到一个伟大的,非人为的用例。也许你在一个表单中有链接字段?


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集合上创建一个额外的错误。





编辑2017年10月24日:


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



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


例如,JSX中的False(React)有一个特殊的含义,即不是在简单的虚假中触发。如果你在JSX中尝试返回类似下面的东西,期望messageCount中的int ... [241]]]


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


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



  • 一个修复涉及bangbang,它0强制!!0false:

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

  • JSX文档建议您更明确,编写自我评论代码,并使用比较强制转换为布尔值。

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

  • 我更自在地用三元组来处理虚假 -

    {messageCount ? <div>You have messages!</div> : false}



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


但是如果你在渲染的JSX中看到奇怪的0,那就考虑松散的虚假管理。

其它参考7


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


true === !!10

false === !!0

其它参考8


它将后缀转换为布尔值。

其它参考9


这是一个双not运算。第一个!将值转换为布尔值并反转其逻辑值。第二个!将逻辑值反转回来。

其它参考10


它模拟Boolean()投射函数的行为。
第一个NOT返回一个布尔值,无论给出什么操作数。第二个NOT否定Boolean值,因此给出变量的true布尔值。最终结果与在值上使用Boolean()函数相同。

其它参考11


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


var foo = "Hello World!";

!foo // Result: false
!!foo // Result: true

其它参考12


!是boolean not,它基本上将enable的值强制转换为其布尔相反的值。第二 !翻转此值。因此,!!enable表示不能启用,将enable的值作为布尔值给出。

其它参考13


我认为值得一提的是,结合逻辑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

其它参考14


!!构造是将任何JavaScript表达式转换为的简单方法
它的布尔等价物。


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

其它参考15


它不是一个单一的运营商,而是两个运营商。它等同于以下内容,是将值转换为布尔值的快速方法。


val.enabled = !(!enable);

其它参考16


我怀疑这是C ++的遗留物,人们会覆盖它!运营商,但不是bool运营商。


因此,要获得负面(或肯定)答案,您首先需要使用!运算符得到一个布尔值,但如果你想检查肯定的情况会使用!!

其它参考17


这里有很多很好的答案,但是如果你已经读过这篇文章了,这有助于我搞定。在Chrome(等)上打开控制台,然后开始输入:


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


当然,这些都只是键入!! someThing,但添加的括号可能有助于使其更容易理解。

其它参考18


ifwhile语句以及?运算符使用真值来确定要运行的代码分支。例如,零和NaN数字以及空字符串为false,但其他数字和字符串为true。对象是真的,但未定义的值和null都是假的。


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



  • 如果x为假值,!xtrue!!xfalse

  • 如果x为真值,!xfalse!!xtrue



当在布尔上下文(ifwhile?)的顶层使用时,!!运算符在行为上是无操作的。例如,if (x)if (!!x)的含义相同。


实际用途



然而,它有几个实际用途。


一种用法是将对象有损压缩到其真值,这样你的代码就不会对一个大对象进行引用并使其保持Activity状态。将!!some_big_object赋值给一个变量而不是some_big_object让我们去它适用于垃圾收集器。这对于产生对象或假值(如null或未定义值(如浏览器特征检测)的情况很有用。


我在答案中提到的另一个用途是关于C对应的!!运算符,它使用lint工具来寻找常见的拼写错误和打印诊断。例如,在C和JavaScript中,有一些常见的拼写错误布尔运算产生其他行为,其输出不是布尔值:



  • if (a = b)是赋值,然后使用b的真值; if (a == b)是一种平等比较。

  • if (a & b)​​]]是一个按位AND; if (a && b)是一个逻辑AND。 2 & 50(假值); 2 && 5是真的。



!!运算符向lint工具保证你写的是你的意思:执行此操作,然后获取结果的真值。


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

其它参考19


!!xBoolean(x)的简写


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

其它参考20


双布尔否定。通常用于检查值是否未定义。

其它参考21


这是一段来自角js的代码


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将是false而且还有一个!这是真的


如果requestAnimationFrame被定义为undefined则
!requestAnimationFrame将是真的,还有一个!这将是错误的

其它参考22


!!它一起使用NOT两次操作,!将值转换为boolean并反转它,这里是一个简单的例子,看看如何!!]]工作原理:


首先你有:


var zero = 0;


然后你做!0,它将被转换为布尔值并被评估为true,因为0是falsy,所以你得到反转值并转换为布尔值,所以它被评估为true


!zero; //true


但是我们不想要反转布尔值的值,所以我们可以再次反转它来得到我们的结果!这就是为什么我们使用另一个!


基本上,!!让我们确定,我们得到的值是布尔值,而不是假的,真理或字符串等......


所以它就像在javascript中使用Boolean函数一样,但是将值转换为布尔值的简单方法更简单:


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

其它参考23


JavaScript中的某些运算符执行隐式类型转换,有时也是如此
用于类型转换。


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


这个事实导致您可以在源代码中看到以下习语:


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

其它参考24


返回变量的布尔值。


相反,可以使用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是否 NOT 定义,而!!a检查变量是否已定义。


!!a!(!a)相同。如果定义aatrue!afalse!!atrue

其它参考25


使用逻辑非运算符两次

意味着!true=false

 和!! !! true=true


其它参考26


在看到所有这些好的答案之后,我想补充使用!!的另一个原因。当我在Angular 2-4(TypeScript)中工作时,我希望在我的用户未经过身份验证时返回一个布尔值false。如果他没有经过身份验证,则令牌字符串将是null]]或""。我可以通过使用下一个代码块来完成此操作:


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

其它参考27


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




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



我只想补充一点


if(variableThing){
  // do something
}


是相同的


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


但是当某些事情未定义时,这可能是一个问题。


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


这里的诀窍是&& s的链将返回它找到的第一个假值 - 这可以被送到if语句等。所以如果b.foo是未定义的,那么将返回undefined并跳过b.foo.bar语句,我们没有错误。


上面的返回未定义但如果你有一个空字符串,false,null,0,undefined这些值将返回,并且很快我们在链中遇到它们 - []{}都是真的。