代码之家  ›  专栏  ›  技术社区  ›  Hexagon Theory

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

  •  2615
  • Hexagon Theory  · 技术社区  · 17 年前

    我看到一些代码似乎使用了一个我不认识的运算符,其形式是两个感叹号,如下所示: !! . 有人能告诉我这个接线员做什么吗?

    我看到的背景是,

    this.vertical = vertical !== undefined ? !!vertical : this.vertical;
    
    34 回复  |  直到 17 年前
        1
  •  2344
  •   user1460043    7 年前

    胁迫 oObject 布尔运算。如果是虚假的(例如0, null , undefined 等等),它将是 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 either an Array or null  
    

    但如果你

    console.log(!!navigator.userAgent.match(/MSIE 8.0/));  
    // returns either true or false
    
        2
  •  785
  •   Lightness Races in Orbit    15 年前

    这是一种非常晦涩的类型转换方法。

    ! 是 不是 . 所以 !true 是 false 和 !false 是 true . !0 是 真 和 !1 是 假 .

    所以你要把一个值转换成一个布尔值,然后反转它,然后再反转它。

    // Maximum Obscurity:
    val.enabled = !!userId;
    
    // Partial Obscurity:
    val.enabled = (userId != 0) ? true : false;
    
    // And finally, much easier to understand:
    val.enabled = (userId != 0);
    
        3
  •  410
  •   Salman Arshad    11 年前

    !!expr 返回布尔值( true 或 false )取决于 真实性 表达方式。当用于非布尔类型时,它更有意义。考虑这些例子,尤其是第三个例子及以后的例子:

              !!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!
    
        4
  •  140
  •   Benny Schmidt    13 年前

    沏茶:

    !! 不是运算符。它是 ! --这是逻辑“not”运算符。


    理论上:

    ! 确定值不是什么的“真相”:

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

    • 事实是 真 不是 假 (这就是为什么 !true 结果 在里面 假 )


    !! 确定值的“真实性” 不 不是:

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

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


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


    在实践中:

    考虑一个简洁的函数,它通过 dynamic typing (又称“鸭子打字”)。我们要编写一个返回 真 如果用户的浏览器支持HTML5 <audio> 元素,但我们不希望函数在 <音频&燃气轮机; 未定义;我们不想使用 try ... catch 处理任何可能的错误(因为它们很严重); 而且 我们不想在函数内部使用一个检查,这个检查不会一致地揭示关于特性的真相(例如, document.createElement('audio') 仍将创建一个名为 <音频&燃气轮机; 即使HTML5 <音频&燃气轮机; 不支持)。


    以下是三种方法:

    // 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 要查找,但它们都会根据比较结果返回不同的值。

    但是等等,还有更多!

    有些人可能注意到,在这个特定的示例中,可以使用 more performant 检查问题对象是否存在的方法 有 财产。有两种方法可以做到这一点:

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

    我们离题了…

    无论这些情况多么罕见,可能存在一些场景,其中最简洁、最有效,因此是获得 真 从非布尔值,可能未定义的值确实是通过使用 !! . 希望这能荒谬地解决问题。

        5
  •  91
  •   Crescent Fresh    17 年前

    !! 将其右侧的值转换为等效的布尔值。(想想可怜人的“类型铸造”方式)。它的 意图 通常是向读者传达代码并不关心 什么 值在变量中,但它是什么 "truth" value 是。

        6
  •  63
  •   Christoph    17 年前

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

    除了这些黑客,您还可以使用与基元类型对应的构造函数函数( 没有 使用 new )要显式地强制转换值,即

    Boolean(foo) === !!foo
    Number(foo)  === +foo
    String(foo)  === ''+foo
    
        7
  •  57
  •   ruffin    7 年前

    有那么多答案做了一半的工作。对, !!X 可以理解为“X的真实性[表示为布尔值]”。但是 !! 实际上,对于弄清楚一个变量是真是假(甚至是多个变量也是假)来说,这不是很重要吗? !!myVar === true 和刚才一样 myVar . 比较 !X! 对于一个“真正的”布尔值并不是很有用。

    你得到什么 !! 是否能够检查多个变量的真实性 互相对抗 以可重复、标准化(和jslint友好)的方式。

    简单铸造:(

    那是…

    • 0 === false 是 false .
    • !!0 === false 是 true .

    上面没有那么有用。 if (!0) 结果与 if (!!0 === false) . 我想不出一个将变量强制转换为布尔值然后与“真”布尔值进行比较的好例子。

    看“=”和“!”=从 JSLint's directions (注:Crockford正在移动他的站点一点;这个链接在某个点上可能会死掉)关于为什么:

    =和!=运算符在比较之前执行类型强制。这是错误的,因为它导致'\t\r\n'==0为真。这会掩盖类型错误。jslint无法可靠地确定==是否正确使用,因此最好不要使用==和!=和总是使用更可靠的==和!==运算符。

    如果你只关心一个值是真实的或不可靠的,那么使用简短的形式。而不是
    (foo != 0)

    只要说
    (foo)

    而不是
    (foo == 0)

    说
    (!foo)

    注意有一些 unintuitive cases 其中布尔值将转换为数字( 真 被铸造成 1 和 假 到 0 )将布尔值与数字进行比较时。在这种情况下, !! 可能在精神上有用。然而,再一次, 在这些情况下,您将非布尔值与硬类型布尔值进行比较,这是一个严重的错误。 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 假 . Look away. It's hideous.

    比较真实性:)

    但是,如果我有两个值,我需要检查是否具有相等的真实性/虚假性呢?

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

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

    所以,唯一真正需要使用“布尔值转换变量”的地方是,如果你有一种情况,你要检查两个变量是否都有 相同的 真实,对吗?也就是说, 使用 !! 如果你需要看两个变量 既真实又虚伪 (或不是),也就是说, 平等的 (或不) 真实性 .

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

    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日,2月19日:

    需要显式布尔值的第三方库

    这是一个有趣的案例… !! 当第三方libs需要显式的布尔值时可能很有用。

    例如, False in JSX (React) has a special meaning 这不是简单的伪造所引发的。如果您试图在JSX中返回如下内容,则在 messageCount …

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

    …看到react呈现 零 当你没有消息的时候。必须显式返回false,JSX才能不呈现。上面的语句返回 零 JSX很高兴地呈现出来。它不能告诉你没有 Count: {messageCount && <div>Get your count to zero!</div>} (或不那么做作的东西)。

    • 其中一个解决办法是强迫 零 进入之内 !!0 ,这就是 假 :
      {!!messageCount && <div>You have messages!</div>}

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

    • 我更愿意自己用三元数来处理错误。--
      {messageCount ? <div>You have messages!</div> : false}

    typescript中的处理方法相同:如果您有一个返回布尔值的函数(或者您正在为布尔变量赋值),则[通常]不能返回/赋值布尔-Y值;它必须是强类型布尔值。这意味着, 敌我识别 myObject 是强类型的 , return !myObject; 适用于返回布尔值的函数,但 return myObject; 没有,你必须 return !!myObject 以符合typescript的期望。

    typescript的例外?如果 我的对象 是一个 any ,你回到了javascript的狂野西部,可以在没有 !! ,即使返回类型是布尔值。

    记住 这些 是JSX&typescript约定吗? 不是Javascript固有的 .

    但如果你觉得奇怪 零 在你渲染的JSX中,考虑宽松的错误管理。

        8
  •  50
  •   Greg    17 年前

    这只是逻辑非运算符,两次-它用于将某些内容转换为布尔值,例如:

    true === !!10
    
    false === !!0
    
        9
  •  30
  •   Paul McMillan    16 年前

    它将后缀转换为布尔值。

        10
  •  24
  •   Bill the Lizard    17 年前

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

        11
  •  22
  •   Prakash    15 年前

    它模拟 Boolean() 铸造功能。 第一 NOT 返回一个布尔值,无论给定的操作数是什么。第二 不是 否定 Boolean 价值,所以给出 true 变量的布尔值。最终结果与使用 布尔() 对值执行函数。

        12
  •  21
  •   Lightness Races in Orbit    14 年前

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

    var foo = "Hello World!";
    
    !foo // Result: false
    !!foo // Result: true
    
        13
  •  18
  •   Annika Backstrom    17 年前

    !是“boolean not”,它本质上把“enable”的值类型转换为它的布尔值。第二!翻转此值。所以, !!enable 意思是“不启用”,给你 enable 作为布尔值。

        14
  •  17
  •   GreQ    10 年前

    我认为值得一提的是,与逻辑和/或组合在一起的条件不会返回布尔值,但在&&和 条件链的第一次成功或最后一次失败。

    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
    
        15
  •  14
  •   Sebastian Simon SamB    11 年前

    这个 !! 构造是将任何javascript表达式转换为 它的布尔等价物。

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

        16
  •  11
  •   Justin Johnson    17 年前

    不是一个接线员,是两个。它等价于以下内容,是将值强制转换为布尔值的快速方法。

    val.enabled = !(!enable);
    
        17
  •  8
  •   Darren Clark    17 年前

    我怀疑这是一个C++的残留物,人们在上面覆盖它!但不是布尔运算符。

    因此,要得到否定(或肯定)的答案,在这种情况下,您首先需要使用!运算符得到一个布尔值,但如果要检查正的情况,将使用!!

        18
  •  8
  •   Damian Yerrick    10 年前

    这个 if 和 while 声明和 ? 运算符使用真值来确定要运行的代码分支。例如,零和NaN数字以及空字符串都是假的,但其他数字和字符串都是真的。对象为真,但未定义的值和 null 都是假的。

    双重否定算子 !! 计算值的真值。实际上是两个操作员, !!x 方法 !(!x) ,其行为如下:

    • 如果 x 是一个错误的值, !x 是 true 和 !X! 是 false .
    • 如果 X

    if (x) if (!!x)

    !!some_big_object some_big_object 我们去垃圾回收站吧。这对于产生对象或假值的情况很有用,例如 无效的 或未定义的值,如浏览器功能检测。

    另一个用途,我在 answer about C's corresponding !! operator 使用“lint”工具查找常见的打字错误和打印诊断。例如,在C和JavaScript中,布尔操作的一些常见错误类型会产生其他输出不太布尔的行为:

    • if (a = b) 赋值后是否使用了 b ; if (a == b) 是一个平等的比较。
    • if (a & b) 是位和; if (a && b) 是一个逻辑与。 2 & 5 是 0 (虚假价值); 2 && 5 是真的。

    这个 !! 操作员向lint工具保证,您所写的就是您的意思:执行此操作,然后获取结果的真值。

    第三种用法是生成逻辑XOR和逻辑XNOR。在C和JavaScript中, a && b 执行逻辑与(如果两边都为真,则为真),以及 a & b 执行按位与。 a || b 执行逻辑或(如果至少有一个为真,则为真),以及 a | b 执行按位“或”。有一个位异或(exclusive or)a s a ^ b ,但没有内置的逻辑XOR运算符(如果只有一侧为真,则为真)。例如,您可能希望允许用户只在两个字段中的一个字段中输入文本。你所能做的就是把每一个都转换成一个真值,然后比较它们: !!x !== !!y .

        19
  •  8
  •   Alireza    7 年前

    !! 它正在使用 NOT 一起操作两次, ! 将值转换为 boolean 相反,这里有一个简单的例子来看看 !! 作品:

    首先,你所在的地方:

    var zero = 0;
    

    然后你这样做 !0 ,它将转换为布尔值并计算为 true 因为0是 falsy ,所以您得到反转的值并转换为布尔值,所以它被计算为 真 .

    !zero; //true
    

    但我们不希望该值的布尔值反转,所以我们可以再次反转该值以获得结果!所以我们用另一个 !

    Boolean

    var zero = 0;
    !!zero; //false
    
        20
  •  7
  •   Sergey Ilinsky    15 年前

        21
  •  7
  •   Warren Davis    12 年前

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

        22
  •  7
  •   Greg Gum    10 年前

    !!x Boolean(x)

        23
  •  5
  •   Sathyam Lokare appiconhero.co    8 年前

    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
    
        24
  •  4
  •   JeevanReddy Avanaganti    11 年前

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

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

    rafSupported = !!requestAnimationFrame ;
    

        25
  •  3
  •   GibboK    11 年前

    用于类型转换。

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

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

    !!x // Same as Boolean(x). Note double exclamation mark
    
        26
  •  3
  •   Ryan Taylor    9 年前

    我只是想补充一下

    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未定义,它将返回未定义并跳过 b.foo.bar 语句,我们不会出错。

    上面的返回未定义,但是如果您有空字符串、false、null、0、undefined,那么这些值将返回,并且一旦在链中遇到它们-- [] 和 {} 都是真实的。

        27
  •  3
  •   efkan    9 年前

    返回变量的布尔值。

    相反, 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
        28
  •  2
  •   user3698272    12 年前
    a = 1;
    alert(!a) // -> false : a is not not defined
    alert(!!a) // -> true : a is not not defined
    

    为了 !a ,它检查 a 是 不是 定义,而 !!a 检查是否定义了变量。

    !A! 是一样的 !(!a) . 如果 一 定义, 一 是 true , !一 是 false 和 !A! 是 真 .

        29
  •  2
  •   Abhay Dixit PrimosK    10 年前

    两次使用逻辑非运算符
    它的意思是!真=假
    而且!真=真

        30
  •  2
  •   Wouter Vanherck    9 年前

    在看到所有这些伟大的答案之后,我想添加另一个使用的原因 !! . 我现在在Angular2-4(typescript)中工作,我想返回一个布尔值作为 false 当我的用户未通过身份验证时。如果他没有通过身份验证,令牌字符串将 null 或 "" . 我可以通过使用下一个代码块来做到这一点:

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