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


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

我看到这个的背景是,

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

2330
2018-04-24 08:13


起源


记住它是“砰,砰,你是布尔” - Gus
只是为了记录,不要做那里引用的内容。做 if(vertical !== undefined) this.vertical = Boolean(vertical);  - 它更干净,更清晰,不需要不必要的任务,完全是标准的,并且速度一样快(在当前的FF和Chrome上) jsperf.com/boolean-conversion-speed 。 - Phil H
!不是运营商。这只是!操作员两次。 - Vivek
只是为了记录, Boolean(5/0) 是不一样的 !!5/0 - schabluk
@schabluk,记录, 操作顺序 是原因 !!5/0 产生 Infinity 而不是 true,由...生产 Boolean(5/0)。 !!5/0 相当于 (!!5)/0  - a.k.a true/0  - 因为 ! 运算符的优先级高于 / 运营商。如果你想布尔化 5/0 使用双重爆炸,你需要使用 !!(5/0)。 - matty


答案:


胁迫 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

2076
2018-04-24 08:18



它将非boolean转换为反向布尔值(例如,!5将为false,因为5是JS中的非假值),然后boolean-inverts,因此您将原始值作为布尔值(因此!! 5将是真实的)。 - Chuck
描述它的一种简单方法是:Boolean(5)=== !! 5;相同的铸造,更少的字符。 - Micah Snyder
这用于将truthy值转换为boolean true,而将falsy值转换为boolean false。 - thetoolman
@Micah Snyder要小心,在JavaScript中最好使用布尔基元,而不是使用新的布尔()创建用布尔框填充的对象。这是一个看到差异的例子: jsfiddle.net/eekbu - victorvartan
据我所知,这个bang-bang模式在if(... _语句)中没有用;只能在应该返回布尔值的函数的return语句中。 - rds


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

! 是 。所以 !true 是 false,和 !false 是 true!0 是 true,和 !1 是 false

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

// Maximum Obscurity:
val.enabled = !!userId;

// Partial Obscurity:
val.enabled = (userId != 0) ? true : false;

// And finally, much easier to understand:
val.enabled = (userId != 0);

733
2017-09-10 17:28



!! false = false。 !! true = true - roosteronacid
(userId == 0) ? false : true; 最小的伤害我的大脑。 - Andy Gaskell
可怕的晦涩......美丽的眉毛简洁到我的眼睛.... - James Westgate
“更容易理解”的变体在这里更容易理解吗?对0的检查不是对0的实际检查,而是对Javascript认为等于0的有些奇怪的值列表进行检查。 userId ? true : false  更清楚地表明正在进行转换并处理userId的值可能已明确设置为的情况 undefined - Ben Regenspan
我的大脑解码没有任何问题 !!var 成 Boolean(var) ..和 !! 更快(处理的指令更少)并且比替代品更短。 - adamJLev


!!expr 返回一个布尔值(true 要么 false)取决于 感实性 的表达。在非布尔类型上使用时更有意义。考虑这些示例,尤其是第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!

376
2018-05-15 09:06



值得注意: !!new Boolean(false) // true - Camilo Martin
...但也 !!Boolean(false) // false - Camilo Martin
new Boolean(false) 是一个对象,即使它包含一个虚假值,一个对象也是真实的! - Salman A
是的,我知道,但考虑到大多数本地构造者的事实(String, Number, Date,等)也可以作为函数调用,但在这种情况下结果是不同的! - Camilo Martin
@SalmanA我也希望javascript有时候有意义:D - Camilo Martin


煮一些茶:

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


理论上:

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

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

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


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

  • 事实是这样的 true 不是   true (这就是为什么 !!true 结果是 true

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


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


在实践中:

考虑一个简洁的功能,通过它来检测功能功能(在这种情况下,平台兼容性) 动态打字 (又名“鸭子打字”)。我们想写一个返回的函数 true 如果用户的浏览器支持HTML5 <audio> 元素,但我们不希望函数抛出错误,如果 <audio> 未定义;我们不想使用 try ... catch 处理任何可能的错误(因为它们很严重); 并且 我们不想在函数内部使用检查,这些检查不能始终如一地揭示该功能的真相(例如, document.createElement('audio') 仍然会创建一个名为的元素 <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

我们离题了......

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


130
2018-02-22 23:45



非常棒的答案,但我没有看到!!的实用性!构造。既然一个 if() 语句已经将表达式强制转换为boolean,显式地将测试函数的返回值强制转换为boolean是多余的 - 因为“真实性”=== true就一个 if()声明无论如何。或者我错过了一个场景,你需要一个truthy表达式实际上是布尔值 true? - Tom Auger
@TomAuger if() 语句会对falsey值进行强制转换,但是你想要在对象上实际设置一个布尔标志 - 它不会像对待它一样 if() 声明。例如 object.hasTheThing = !!castTheReturnValToBoolNoMatterWhat() 会设置 true 要么 false 而不是真正的返回值。另一个例子可能是所有管理员都是 id 的 0 和非管理员是id 1 或更高。要得到 true 如果有人不是管理员,你可以做 person.isNotAdmin = !!admin.id。很少有用例,但有时会很简洁。 - Benny Schmidt


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


87
2017-09-10 17:26



或者在右边的布尔值的情况下,它什么都不做。 - Daniel A. White
@Daniel: ! 仍然将价值翻转到右边。在布尔最右边的情况下 ! 否定价值,而最左边 ! 再次否定它。净效应是没有变化,但大多数引擎将生成双重否定的操作码。 - Crescent Fresh
但重点是什么?如果我做 if(0){... Javascript已经知道这是错误的。为什么说更好 if(!!0){...? - CodyBugstein
关键是您可能不知道其内容的变量;如果它可以是整数或字符串,对象或null,未定义等。这是测试存在的简单方法。 - mix3d


!!foo 应用unary not运算符两次并用于转换为类似于使用unary plus的布尔类型 +foo 转换为数字并连接空字符串 ''+foo 转换为字符串。

您也可以使用与基元类型对应的构造函数来代替这些黑客攻击( 运用 new)明确地施放价值,即

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

59
2017-09-10 21:15



但是你可以遇到instanceof的问题。 new Boolean(1)instanceof Object - > true !! 1 instanceof Object - > false - Seamus
不,你不能:注意没有调用构造函数 new  - 正如我的回答中明确提到的那样 - Christoph
太棒了!当你需要将“0”的字符串评估为false而不是true时,这对于一点点黑客很有用。 (即从选择中读取值时,因为它们被读作String)。所以,如果你想把“0”视为负数(布尔值为false),那么 x="0" 做就是了: x=!!+x; //false 这是一样的 Boolean(Number(x)) Number(或+ x)将字符串“0”转换为0,将其评估为false,然后将Boolean(!! x)直接转换为boolean。十分简单! - DiegoDD
@DiegoDD你为什么选择 !!+x VS x !== "0"? - placeybordeaux
@placeybordeaux因为您可能想要转换该值并将其分配给其他变量,无论您是否要将其与其他变量进行比较。 - DiegoDD


这么多答案做了一半的工作。是, !!X 可以被解读为“X的真实性[表示为布尔]”。但 !! 实际上,对于确定单个变量是否(或者即使许多变量是真实的)真实或虚假也是如此重要。 !!myVar === true 和刚刚一样 myVar。对比 !!X 到“真正的”布尔值并不是真的有用。

你获得了什么 !! 能够检查多个变量的真实性 互相攻击 以可重复,标准化(和JSLint友好)的方式。

简单铸造:(

那是...

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

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

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

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

如果您只关心某个值是真或假,那么请使用简短形式。代替
(foo != 0)

说啊
(foo)

而不是
(foo == 0)


(!foo)

请注意,有一些 不直观的案件 将布尔值强制转换为数字(true 被投射到 1 和 false 至 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,这将在消息框中输出-1!在cmd.exe提示符下尝试,看看!但 WScript.echo(-1 == test()) 仍然给你0或WScript false把目光移开这很可怕。

比较真实:)

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

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

  • myVar1 === myVar2 是 0 === 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.";
}

所以现在,如果你有两个真正的truthy 要么 对于配偶姓名和年龄都是假的,你可以继续。否则你只有一个具有价值的领域(或者一个非常早期的婚姻),并且需要在你的领域产生额外的错误 errorObjects 采集。


编辑2017年10月24日: 

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

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

例如, JSX(React)中的False具有特殊含义 这不是简单的虚假引发的。如果您尝试在JSX中返回类似以下内容的内容,则需要使用int messageCount...

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

......你可能会惊讶地发现React渲染了一个 0 当你有零消息。您必须为JSX显式返回false才能呈现。上述声明返回 0,JSX愉快地呈现,应该如此。它不能告诉你没有 Count: {messageCount && <div>Get your count to zero!</div>} (或者不那么做作的东西)。

  • 一个修复涉及强迫的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}

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

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


47
2018-04-29 18:14



很好的解释。所以你会说!!在这方面并不是绝对必要的 工人特征检测 例? if (!!window.Worker) - jk7
不,你不需要它。真实和 true “外部”操作完全相同 if。我一直在尝试,但我想不出有理由倾向于将真实性转换为上述复杂的“比较真实性”情况之外的布尔值,除非您以后重复使用该值时的可读性,如 q 图书示例。但即便如此,这也是一个信息损失的捷径,我认为你最好每次评估真实性。 - ruffin
React是我们开始使用!!的主要原因!模式,但它恰好是一个非常方便和可重复的事情。我只需要担心某事的真实性或虚假性,而不是基本类型的真实性或虚假性。 - Alexander Pritchard


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

true === !!10

false === !!0

44
2018-04-24 08:18



为什么你会这样做?使用 !运算符转换为布尔值然后使用===比较类型?只是接受你没有类型安全,并做val> 0或其他什么。 - Darren Clark
@Darren:他不是在比较类型;他通过在答案中写下断言告诉你结果是什么。 - Lightness Races in Orbit


它将后缀转换为布尔值。


28
2017-09-10 17:27





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


21
2017-09-10 17:28





它模拟了行为 Boolean() 铸造功能。 首先 NOT 无论给出什么操作数,都返回一个布尔值。第二 NOT 否定这一点 Boolean 价值等等给出了 true变量的布尔值。最终结果与使用相同 Boolean() 函数值。


21
2018-03-23 11:53