首页 文章

是什么 !! (不是)JavaScript中的运算符?

提问于
浏览
2511

我看到一些代码似乎使用了一个我无法识别的运算符,以两个感叹号的形式出现,如下所示: !! . 有人可以告诉我这个运营商做了什么?

我看到这个的背景是,

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

30 回答

  • 54

    这么多答案做了一半的工作 . 是的, !!X 可以读作"the truthiness of X [represented as a boolean]" . 但是,实际上, !! 对于确定单个变量是否(或者即使许多变量是真实的)是真实的还是非常重要的 . !!myVar === truemyVar 相同 . 将 !!X 与"real"布尔值进行比较并不是很有用 .

    你通过_259008获得的是能够以可重复的,标准化的(和JSLint友好的)方式相互检查多个变量的真实性 .

    简单铸造:(

    那是...

    • 0 === falsefalse .

    • !!0 === falsetrue .

    以上不太有用 . if (!0) 为您提供与 if (!!0 === false) 相同的结果 . 我想不出将变量转换为布尔值然后与"true"布尔值进行比较的好例子 .

    请参阅JSLint's directions中的"== and !="(注意:Crockford正在移动他的网站一点;这个链接可能会在某些时候死亡),原因如下:

    ==和!=运算符在比较之前键入强制 . 这很糟糕,因为它会导致'\ t \ r \ n'== 0为真 . 这可以掩盖类型错误 . JSLint无法可靠地确定是否正确使用==,因此最好不要使用==和!=并始终使用更可靠的===和!==运算符 . 如果您只关心某个值是真或假,那么请使用简短形式 . 而不是(foo!= 0)只说(foo)而不是(foo == 0)说(!foo)

    请注意,在将布尔值与数字进行比较时,有一些unintuitive cases,其中布尔值将强制转换为数字( true 转换为 1false 转换为 0 ) . 在这种情况下, !! 可能在精神上有用 . 虽然,再次, these are cases where you're comparing a non-boolean to a hard-typed boolean, which is, imo, a serious mistake. 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());
    

    因为some historical Windows jive,所以在消息框中输出-1!在cmd.exe提示符下尝试,看看!但 WScript.echo(-1 == test()) 仍然给你0,或WScript的 false . Look away. It's hideous.

    比较真实性:)

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

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

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

    • !!myVar1 === !!myVar2!!0 === !!undefined 并且是真的!同样诚实! (在这种情况下,两者都是"have a truthiness of falsy" . )

    所以你唯一可以检查两个变量是否具有相同的真实性,对吗?那就是 use !! if you need to see if two vars are both truthy or both falsy (or not), that is, of equal (or not) truthiness.

    我无法想到一个伟大的,非人为的用例 . 也许你在表单中有“链接”字段?

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


    EDIT 24 Oct 2017:

    3期望显式布尔值的派对库

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

    例如,False in JSX (React) has a special meaning不会因简单的虚假而触发 . 如果您尝试在JSX中返回类似以下内容的内容,则期望 messageCount 中的int ...

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

    ...当你没有消息时,你可能会惊讶地看到React呈现 0 . 您必须为JSX显式返回false才能呈现 . 上面的语句返回 0 ,这是JSX愉快地呈现的,应该如此 . 它可以't tell you didn'(或者更少做作的东西) .

    • 一个修复涉及bangbang,它将 0 强制转换为 !!0 ,这是 false
      {!!messageCount && <div>You have messages!</div>}

    • JSX'文档建议你更明确,编写自我评论代码,并使用比较强制转换为布尔值 .
      {messageCount > 0 && <div>You have messages!</div>}

    • 我更自在地用三元组来处理虚假 -
      {messageCount ? <div>You have messages!</div> : false}

    请记住 this is a JSX convention, not one inherent to JavaScript .

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

  • 2249

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

    !是"boolean not",它基本上将"enable"的值强制转换为其布尔相反的值 . 第二 !翻转此值 . 所以, !!enable 表示"not not enable,"给你 enable 的值作为布尔值 .

  • 11

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

    这是一段来自角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被uninged undefined那么!requestAnimationFrame将是真的,还有一个!这将是错误的

  • 138

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

  • 7

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

    首先,你有:

    var zero = 0;
    

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

    !zero; //true
    

    但我们不知道为什么我们使用另一个 ! .

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

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

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

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

  • 47

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

    val.enabled = !(!enable);
    
  • 8

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

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

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

  • 3

    这里有很多很好的答案,但如果你读到这么远,这有助于我“得到它” . 在Chrome(等)上打开控制台,然后输入:

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

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

  • 3

    我只想补充一点

    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
    

    这里的技巧是 && 的链将返回它找到的 the first falsey value - 这可以被提供给if语句等等 . 所以如果b.foo是未定义的,它将返回undefined并跳过 b.foo.bar 语句,我们没有得到任何错误 .

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

  • 4

    Brew some tea:

    !! 不是运营商 . 它是 ! 的两次使用 - 这是逻辑"not"运算符 .


    In theory:

    ! 确定"truth"的值不是:

    • 事实是 false 不是 true (这就是 !false 导致 true 的原因)

    • 事实是 true 不是 false (这就是 !true 导致 false 的原因)


    !! 确定"truth"的值不是:

    • 事实是 true 不是 true (这就是 !!true 导致 true 的原因)

    • 事实是 false 不是 false (这就是 !!false 导致 false 的原因)


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


    In practice:

    考虑一个简洁的功能,它通过 dynamic typing (又名"duck typing")检测功能功能(在这种情况下,平台兼容性) . 我们想编写一个函数,如果用户的浏览器支持HTML5 <audio> 元素,则返回 true ,但如果 <audio> 未定义,我们不希望该函数抛出错误;我们不想使用 try ... catch 来处理任何可能的错误(因为它们很严重);而且我们也不断透露有关该功能的真相(例如,即使不支持HTML5 <audio>document.createElement('audio') 仍会创建一个名为 <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 ,但它们每个都会根据比较确定的值返回不同的值 .

    But wait, there's more!

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

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

    We digress...

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

  • 7

    !! 将其右侧的值转换为其等效的布尔值 . (想想穷人的方式"type-casting") . 它的目的通常是向读者传达代码并不关心变量中的值是什么,而是"truth" value是什么 .

  • 89

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

    ! 不是 . 所以 !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);
    
  • 13

    我怀疑这是C的遗留物,人们会超越它!运营商,但不是bool运营商 .

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

  • 62

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

    它将后缀转换为布尔值 .

  • 767

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

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

    • 如果 x 是假值, !xtrue!!xfalse .

    • 如果 x 是真值, !xfalse!!xtrue .

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

    实际用途

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

    一种用法是将对象有损压缩到其真值,这样您的代码就不会持有对大对象的引用并使其保持活动状态 . 将 !!some_big_object 分配给变量而不是 some_big_object ,可以将其用于垃圾收集器 . 这对于生成对象或false值(例如 null )或未定义值(例如浏览器功能检测)的情况非常有用 .

    我在answer about C's corresponding !! operator中提到的另一个用途是使用"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 .

  • 20

    返回变量的布尔值 .

    相反,可以使用 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
    
  • 21

    !!xBoolean(x) 的简写

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

  • 16

    它迫使所有事情都布尔 .

    例如:

    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
    
  • 2
    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 .

  • 9

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

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

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

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

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

    使用logical not运算符两次
    it means !true= false and !!true = true

  • 2

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

    true === !!10
    
    false === !!0
    
  • 402

    !! 构造是将任何JavaScript表达式转换为其布尔等效项的简单方法 .

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

  • 4

    JavaScript中的某些运算符执行隐式类型转换,有时用于类型转换 .

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

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

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

相关问题