是啥 !! JavaScript 中的(不是否)运算符?

Posted

技术标签:

【中文标题】是啥 !! JavaScript 中的(不是否)运算符?【英文标题】:What is the !! (not not) operator in JavaScript?是什么 !! JavaScript 中的(不是不是)运算符? 【发布时间】:2010-11-27 06:08:08 【问题描述】:

我看到一些代码似乎使用了我不认识的运算符,以两个感叹号的形式出现,例如:!!。谁能告诉我这个运算符是做什么的?

我看到这个的背景是,

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

【问题讨论】:

通过“砰,砰,你是布尔值”记住它 只是为了记录,不要做那里引用的事情。执行if(vertical !== undefined) this.vertical = Boolean(vertical); - 正在发生的事情更加清晰明了,不需要不必要的分配,完全是标准的,并且同样快(在当前的 FF 和 Chrome 上)jsperf.com/boolean-conversion-speed。 !!不是运算符。这只是!运算符两次。 @schabluk,记录在案,order of operations 是!!5/0 产生Infinity 而不是true 产生的原因,Boolean(5/0) 产生。 !!5/0 等价于 (!!5)/0 -- 又名 true/0 -- 因为 ! 运算符的优先级高于 / 运算符。如果您想使用双键布尔化 5/0,则需要使用 !!(5/0) @Gus 你知道吗,我早在 2012 年就读过你的评论了。从那以后的 7 年里,我一直在心里幽默地说“砰砰!你是布尔值!”在反转布尔值时,我一直记得结果如何。我决定今天查看您的评论并让您知道:-) 【参考方案1】:

Object 转换为boolean。如果是假的(例如0nullundefined等),则为false,否则为true

!oObject  // inverted boolean
!!oObject // non inverted boolean so true boolean representation

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

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

const 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

【讨论】:

它将非布尔值转换为反转布尔值(例如,!5 为假,因为 5 在 JS 中是非假值),然后布尔反转,因此您得到原始值一个布尔值(所以 !!5 为真)。 一个简单的描述方式是:Boolean(5) === !!5;相同的演员阵容,更少的字符。 这用于将truthy值转换为boolean true,falsy值转换为boolean false。 @Micah Snyder 请注意,在 javascript 中最好使用布尔原语,而不是使用 new Boolean() 创建将布尔值框起来的对象。这是一个查看差异的示例:jsfiddle.net/eekbu 据我所知,这种 bang-bang 模式在 if(..._ 语句中没有用;仅在应该返回布尔值的函数的 return 语句中。【参考方案2】:

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

! 表示。所以!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);

【讨论】:

!!假=假。 !!真=真 这里的“更容易理解”变体真的更容易理解吗?对 0 的检查不是对 0 的实际检查,而是对 Javascript 认为等于 0 的有点奇怪的值列表进行检查。userId ? true : false 更清楚地表明正在进行转换并处理 userId 的值可能已经存在的情况明确设置为undefined 我的大脑在将!!var 解码为Boolean(var) .. 时没有任何问题,而!! 比其他方法更快(处理指令更少)并且更短。 !!false 是假的。 false != 0 是真的。所以它们不是等价的。 !! 用于将 anything 强制为布尔值。 我知道你在很多年前写了这个答案,但为了今天的改进:最容易理解的是说出你的意思Boolean(x)。我认为您的任何替代方案都不容易理解。更糟糕的是,至少在一种情况下,使用相等运算符x != 0 会得到与Boolean(x)!!x 不同的结果:尝试[] for x。另外,如果您确实喜欢使用相等运算符来获得其“真实性”规则,为什么不使用更明显的(userId == true) 而不是(userId != 0)【参考方案3】:

!!expr(两个! 运算符后跟一个表达式)根据表达式的真实性 返回一个布尔值(truefalse)。在非布尔类型上使用时更有意义。考虑这些示例,尤其是第三个示例及以后的示例:

          !!false === false
           !!true === true

              !!0 === false
!!parseInt("foo") === false // NaN is falsy
              !!1 === true
             !!-1 === true  // -1 is truthy
          !!(1/0) === true  // Infinity 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 value is falsy
      !!undefined === false // undefined primitive is falsy
           !!null === false // null is falsy

             !! === true  // an (empty) object is truthy
             !![] === true  // an (empty) array is truthy; php programmers beware!

【讨论】:

值得注意:!!new Boolean(false) // true ...还有!!Boolean(false) // false new Boolean(false) 是一个对象,一个对象是真的,即使它包含一个假值! 明确建议将!!undefined //false 添加到这个出色的答案中! @SalmanA 扩展为您的正确评论 !!(new Boolean(false).valueOf()) // false (因为 new Boolean 返回一个 Boolean 对象的实例,这是真实的,而 Boolean(false) 或 Boolean valueOf() 将表达式的值强制为原始布尔值)。【参考方案4】:

泡茶:

!! 不是运算符。它是! 的双重用途——它是逻辑“非”运算符。


理论上:

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

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

事实是true 不是false(这就是!true 结果的原因 在 false)


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

事实是 true 不是 not true(这就是为什么 !!true 会导致 true

事实是 false 不是 not false(这就是为什么 !!false 会导致 false


我们希望在比较中确定的是关于引用值的“真相”,而不是引用本身的。有一个用例,我们可能想知道一个值的真相,即使我们期望该值是false(或错误),或者如果我们期望该值不是typeof boolean.


在实践中:

考虑一个简洁的函数,它通过 dynamic typing(又名“duck typing”)检测特性功能(在本例中为平台兼容性)。如果用户的浏览器支持 html5 <audio> 元素,我们想编写一个返回 true 的函数,但如果 <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

每个函数都接受要查找的 &lt;tag&gt;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

我们离题了...

尽管这些情况可能很少见,但可能存在一些场景,其中最简洁、最高效、因此最优选的从非布尔值、可能未定义的值获取 true 的方法确实是使用 !! .希望这可笑地清除它。

【讨论】:

非常棒的答案,但我看不到 !!构造。由于if() 语句已经将表达式转换为布尔值,因此将测试函数的返回值显式转换为布尔值是多余的——因为就if() 语句而言,“真实性” === true。还是我错过了一个场景,您需要一个真实的表达式才能真正成为布尔值true @TomAuger if() 语句确实将布尔值转换为虚假值,但说您想在对象上实际设置一个布尔标志 - 它不会像 if() 语句那样转换它。例如object.hasTheThing = !!castTheReturnValToBoolNoMatterWhat() 将设置truefalse 而不是真正的返回值。另一个例子是可能所有管理员都是id0,而非管理员的id 是1 或更高。要获得true,如果某人不是管理员,您可以使用person.isNotAdmin = !!admin.id。用例很少,但有的时候很简洁。【参考方案5】:

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

【讨论】:

或者在右边的布尔值的情况下,它什么也不做。 @Daniel: ! 仍然将值翻转到右侧。在布尔值的情况下,最右边的! 否定该值,而最左边的! 再次否定它。净效果是没有变化,但大多数引擎会生成双重否定的操作码。 但是有什么意义呢?如果我这样做 if(0)... Javascript 已经知道这是错误的。为什么说if(!!0)...更好? 重点是你可能不知道其内容的变量;如果它可以是整数或字符串、对象或 null、未定义等。这是测试存在性的简单方法。【参考方案6】:

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

除了这些技巧之外,您还可以使用与原始类型对应的构造函数(不使用使用new)来显式转换值,即

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

【讨论】:

但是你可能会遇到 instanceof 的问题。 new Boolean(1) instanceof Object -> true !!1 instanceof Object -> false 不,您不能:请注意,在没有 new 的情况下调用构造函数 - 正如我的回答中明确提到的那样 太棒了!当您需要将带有“0”的字符串评估为假而不是真时,这对于一些小技巧很有用。 (即从选择中读取值时,因为它们被读取为字符串)。因此,如果您想将“0”视为负数(布尔值 false),假设 x="0" 只需执行以下操作:x=!!+x; //falseBoolean(Number(x)) 相同 Number(或 +x)将字符串“0”转换为 0,它的评估结果为假,然后布尔 (!!x) 直接将其转换为布尔值。轻松愉快! @DiegoDD 你为什么选择!!+xx !== "0" @placeybordeaux 因为例如您可能想要转换该值并将其分配给其他变量,无论您是否要将其与其他变量进行比较。【参考方案7】:

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

您使用!! 获得的唯一好处是能够以可重复、标准化(且 JSLint 友好)的方式检查多个变量的真实性相互

简单转换:(

那是……

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

上面的用处不大。 if (!0) 为您提供与 if (!!0 === false) 相同的结果。我想不出将变量转换为布尔值然后与“真”布尔值进行比较的好案例。

请参阅来自 JSLint's directions 的“== 和 !=”(注意:Crockford 正在稍微移动他的网站;该链接可能会在某个时候失效)以了解原因:

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

如果您只关心一个值是真还是假,那么请使用简写形式。而不是 (foo != 0)

只是说 (foo)

而不是 (foo == 0)

(!foo)

请注意,在将布尔值与数字进行比较时,有一些 unintuitive cases 会将布尔值转换为数字(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());

由于some historical Windows jive,这将在消息框中输出-1!在 cmd.exe 提示符下试试看!但是WScript.echo(-1 == test()) 仍然给你0,或者WScript 的false。 Look away. It's hideous.

比较真实性:)

但是,如果我需要检查两个值是否相等,该怎么办?

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

myVar1 === myVar20 === 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 日,19 年 2 月 6 日编辑:

第三方库需要明确的布尔值

这是一个有趣的案例...!! 在 3rd 方库需要明确的布尔值时可能很有用。

反应

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

messageCount &amp;&amp; &lt;div&gt;You have messages!&lt;/div&gt;

...当您的消息为零时,您可能会惊讶地看到 React 呈现 0。您必须显式返回 false 才能使 JSX 不呈现。上面的语句返回 0,JSX 很高兴地呈现它,正如它应该的那样。它不能告诉你没有Count: messageCount

一个修复涉及到 bangbang,它将 0 强制转换为 !!0,即 false!!messageCount &amp;&amp; &lt;div&gt;You have messages!&lt;/div&gt;

JSX 的文档建议您更加明确,编写自注释代码,并使用比较来强制为布尔值。messageCount &gt; 0 &amp;&amp; &lt;div&gt;You have messages!&lt;/div&gt;

我更愿意自己用三元处理虚假 --messageCount ? &lt;div&gt;You have messages!&lt;/div&gt; : false

打字稿

Typescript 中的相同处理:如果您有一个返回布尔值的函数(或者您正在为布尔变量分配一个值),那么您 [通常] 不能返回/分配一个 boolean-y 值;它必须是强类型的布尔值。这意味着,如果 myObject 是强类型return !myObject; 适用于返回布尔值的函数,但 return myObject; 不适用。您必须 return !!myObject(或以另一种方式转换为正确的布尔值)才能符合 Typescript 的期望。

Typescript 的例外?如果 myObjectany,那么您又回到了 JavaScript 的狂野西部,并且可以在没有 !! 的情况下返回它,即使您的返回类型是布尔值。

请记住,这些是 JSX 和 Typescript 约定,而不是 JavaScript 固有的

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

【讨论】:

很好的解释。所以你会说!!在这个Worker feature detection 示例中不是绝对必要的吗? if (!!window.Worker) 不,你不需要它。真实性和true“外部”在if 中的操作完全相同。我一直在尝试,但我想不出有什么理由更喜欢将真实性转换为布尔值,而不是上面那种令人费解的“比较真实性”案例,除非你稍后重用该值时的可读性,如@987654387 @ 库示例。但即便如此,这也是一种信息丢失的捷径,我认为你最好每次都评估真实性。【参考方案8】:

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

true === !!10

false === !!0

【讨论】:

【参考方案9】:

它将后缀转换为布尔值。

【讨论】:

【参考方案10】:

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

【讨论】:

【参考方案11】:

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

var foo = "Hello World!";

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

【讨论】:

【参考方案12】:

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

【讨论】:

【参考方案13】:

!! 它同时使用了两次NOT 操作,! 将值转换为boolean 并将其反转,因此使用它两次,显示该值的布尔值(false 或 true)。这是一个简单的例子,看看!! 是如何工作的:

首先,你拥有的地方:

var zero = 0;

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

!zero; //true

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

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

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

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

【讨论】:

【参考方案14】:

!是“布尔非”,它本质上将“启用”的值类型转换为其布尔值的对立面。第二 !翻转这个值。因此,!!enable 表示“未启用”,将 enable 的值作为布尔值提供给您。

【讨论】:

【参考方案15】:

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

【讨论】:

【参考方案16】:

这不是一个运算符,而是两个。它等效于以下内容,是一种将值转换为布尔值的快速方法。

val.enabled = !(!enable);

【讨论】:

【参考方案17】:

!! 构造是一种将任何 JavaScript 表达式转换为 它的布尔等价物。

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

【讨论】:

非常接近重要的区别。 关键是0 === false 为假,!!0 === false 为真。【参考方案18】:

这个问题已经回答得相当彻底了,但我想补充一个我希望尽可能简化的答案,使 !!尽可能简单地掌握。

因为 javascript 具有所谓的“真”和“假”值,所以有些表达式在其他表达式中求值时会产生真或假条件,即使正在检查的值或表达式实际上不是 truefalse

例如:

if (document.getElementById('myElement')) 
    // code block

如果该元素确实存在,则表达式将评估为真,并执行代码块。

但是:

if (document.getElementById('myElement') == true) 
    // code block

...不会产生真条件,并且代码块不会被执行,即使元素确实存在。

为什么?因为document.getElementById() 是一个“真实”表达式,在此if() 语句中将评估为真,但它不是true 的实际布尔值。

在这种情况下,双“非”非常简单。它只是两个nots 背靠背。

第一个简单地“反转”真值或假值,产生一个实际的布尔类型,然后第二个“反转”它再次回到它的原始状态,但现在是一个实际的布尔值。这样你就有了一致性:

if (!!document.getElementById('myElement')) 

if (!!document.getElementById('myElement') == true) 

两者都将返回 true,如预期的那样。

【讨论】:

【参考方案19】:

我怀疑这是 C++ 的遗留问题,人们会覆盖 !运算符,但不是布尔运算符。

因此,在这种情况下,要获得否定(或肯定)答案,您首先需要使用 !运算符获取布尔值,但如果您想检查肯定的情况,请使用 !!。

【讨论】:

【参考方案20】:

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

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

如果x 为假值,则!xtrue!!xfalse。 如果x 为真值,则!xfalse!!xtrue

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

实际用途

但是它有几个实际用途。

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

我在answer about C's corresponding !! operator 中提到的另一个用途是使用“lint”工具来查找常见的拼写错误和打印诊断。例如,在 C 和 JavaScript 中,布尔运算的一些常见拼写错误会产生其他行为,其输出与布尔运算不同:

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

!! 运算符向 lint 工具保证你写的就是你的意思:做这个操作,然后取结果的真值。

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

【讨论】:

【参考方案21】:

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

【讨论】:

【参考方案22】:

!!xBoolean(x) 的简写

第一个 bang 强制 js 引擎运行Boolean(x) 但也有取反的副作用。所以第二次爆炸消除了副作用。

【讨论】:

【参考方案23】:

它强制所有东西都是布尔值。

例如:

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】:

我只是想补充一下

if(variableThing)
  // do something

相同
if(!!variableThing)
  // do something

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

// a === undefined, b is an empty object (eg. b.asdf === undefined)
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

这里的技巧是&amp;&amp;s 的链将返回它找到的第一个错误值——这可以提供给 if 语句等。所以如果 b.foo 未定义,它将返回 undefined 并跳过 b.foo.bar 语句,我们不会收到错误。

上面的返回 undefined 但是如果你有一个空字符串,false, null, 0, undefined 这些值将会返回,并且一旦我们在链中遇到它们——[] 都是“真实的”和我们将继续沿着所谓的“&& 链”到右边的下一个值。

P.S. 执行上述操作的另一种方法 (b &amp;&amp; b.foo) 是 (b || ).foo。这些是等效的,因为如果 b 未定义,则 b || 将是 ,并且您将访问空对象中的值(无错误)而不是尝试访问“未定义”中的值(导致错误)。

所以,(b || ).foob &amp;&amp; b.foo 相同,((b || ).foo || ).barb &amp;&amp; b.foo &amp;&amp; b.foo.bar 相同。

【讨论】:

好点——改变了我的答案。它只会在嵌套三层深度的对象上发生,因为就像你说的().anything 会给出undefined【参考方案25】:

这里有很多很棒的答案,但如果你已经读到这里,这有助于我“明白”。在 Chrome(等)上打开控制台,然后开始输入:

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

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

【讨论】:

【参考方案26】:

在看到所有这些很棒的答案后,我想添加另一个使用!! 的原因。目前我正在使用 Angular 2-4 (TypeScript),当我的用户未通过身份验证时,我想返回一个布尔值作为 false。如果他未通过身份验证,则令牌字符串将为null""。我可以通过使用下一个代码块来做到这一点:

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

【讨论】:

【参考方案27】:

这是一段来自 Angular 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 会是假的,还有一个!应该是真的

如果 requestAnimationFrame 被分配为 undefined 则 !requestAnimationFrame 将是真的,还有一个!应该是假的

【讨论】:

【参考方案28】:

返回一个变量的布尔值。

相反,可以使用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正在使用中。

请检查下面的代码 sn-p

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

【讨论】:

Upvoted.. 如果还没有,实际上会回答这个问题。从可读性的角度来看,使用布尔对象 imo 是一种更好的方法。例如,没有“布尔值做什么”的 SO 问题,3k 加赞成票 - 就像当前的问题一样。【参考方案29】:

使用逻辑非运算符两次意思是 !true = false !!true = true

【讨论】:

【参考方案30】:

记住在 JavaScript 中对 truefalse 的评估很重要:

所有带有“值”的都是true(即truthy),例如:

101, 3.1415, -11, "Lucky Brain", new Object() 当然还有true

没有“值”的所有内容都是false(即falsy),例如:

0, -0, ""(空字符串), undefined, null, NaN(不是数字) 当然还有false

应用“逻辑非”运算符 (!) 计算操作数,将其转换为 boolean,然后取反。应用它两次将否定否定,有效地将值转换为boolean。不应用运算符将​​只是对确切值的常规分配。例子:

var value = 23; // number
var valueAsNegatedBoolean = !value; // boolean falsy (because 23 is truthy)
var valueAsBoolean = !!value; // boolean truthy
var copyOfValue = value; // number 23

var value2 = 0;
var value2AsNegatedBoolean = !value2; // boolean truthy (because 0 is falsy)
var value2AsBoolean = !!value2; // boolean falsy
var copyOfValue2 = value2; // number 0
value2 = value; 分配确切的对象value,即使它不是boolean,因此value2 不一定最终是booleanvalue2 = !!value; 分配有保证的 boolean 作为操作数 value 的双重否定的结果,它等效于以下内容,但更短且可读性更强:

if (value) 
  value2 = true;
 else 
  value2 = false;

【讨论】:

这如何为其他答案添加新的或有用的东西? 其他答案都没有阐明 JavaScript 如何评估 truthyfalsy 的概念。新手 JavaScript 开发人员需要知道“not not”运算符隐式使用原始的松散比较方法,而不是精确的 ===!== 运算符,以及在幕后发生的隐藏转换操作,我在我提供的例子。

以上是关于是啥 !! JavaScript 中的(不是否)运算符?的主要内容,如果未能解决你的问题,请参考以下文章

是啥 !! JavaScript 中的(不是否)运算符?

是啥? JavaScript 中的语法是啥意思?

JavaScript 中的 ?: 语法是啥? [复制]

mysql表中的javascript多维数组-不知道那种对象对象是啥

传播功能是啥意思。 javascript中的普通函数是不是可迭代

javascript 中的window对象是啥