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

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

我看到这个的背景是,

this.vertical = vertical !== undefined ? !!vertical : this.vertical;
849923 次浏览

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

!object  // Inverted Boolean!!object // Noninverted Boolean, so true Boolean representation

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

这样做可能更简单:

Boolean(object) // Boolean

真实世界示例“测试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

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

true === !!10
false === !!0

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

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

我怀疑这是C++的残余,人们覆盖了!操作符,但不是bool操作符。

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

!!将其右边的值转换为其等效的布尔值。(想想穷人的“类型转换”方式。)它的意图通常是向读者传达代码不在乎什么值在变量中,而是它的“真实”值是什么。

它将后缀转换为布尔值。

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

!意味着不是。所以!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);
// Or justval.enabled = Boolean(userId);

备注:后两个表达式在某些边缘情况下(例如,当userId[]时)并不完全等同于第一个表达式,这是由于!=运算符的工作方式和Truthy所考虑的值。

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

!是“Boolean not”,它本质上将“able”的值转换为其布尔值的对立面。第二个!翻转此值。因此,!!enable表示“不启用”,为您提供enable的布尔值。

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

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

Boolean(foo) === !!fooNumber(foo)  === +fooString(foo)  === ''+foo

它不是一个运算符;它是两个。它相当于以下内容,是将值转换为布尔值的快速方法。

val.enabled = !(!enable);

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

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

这是一个非常方便的方法来检查未定义,“未定义”,null,“null”,“”

if (!!var1 && !!var2 && !!var3 && !!var4 ){//... some code here}

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

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

泡茶:

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


理论上:

#0确定了一个值不是什么的“真相”:

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

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


#0确定一个值的“真相”没有不是:

  • 事实是true不是没有true(这就是为什么!!true会导致#0

  • 事实是false不是没有false(这就是为什么!!false会导致#0


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


在实践中:

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


以下是三种方法:

// this won't tell us anything about HTML5 `<audio>` as a featurevar 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 wantvar baz = function(tag, atr) { return !!document.createElement(tag)[atr]; }
foo('audio', 'preload'); // returns "auto"bar('audio', 'preload'); // returns falsebaz('audio', 'preload'); // returns true

每个函数都接受要查找的<tag>attribute的参数,但它们都根据比较确定的内容返回不同的值。

等等,还有更多!

你们中的一些人可能注意到,在这个特定的例子中,可以使用稍微性能更佳的方法来检查一个属性,即检查有问题的对象已经是否是一个属性。有两种方法可以做到这一点:

// the native `hasOwnProperty` methodvar qux = function(tag, atr) { return document.createElement(tag).hasOwnProperty(atr); }
// the `in` operatorvar quux = function(tag, atr) { return atr in document.createElement(tag); }
qux('audio', 'preload');  // returns truequux('audio', 'preload'); // returns true

我们离题…

无论这些情况多么罕见,可能存在一些场景,其中最简洁、最高性能、因此也是最首选的从非布尔值(可能是未定义的值)中获取true的方法确实是使用!!。希望这荒谬地清除了它。

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

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

这里有很多很好的答案,但是如果你已经读了这么远,这有助于我理解它。在Chrome(等)中打开控制台,然后开始输入:

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

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

a = 1;alert(!a) // -> false : a is not not definedalert(!!a) // -> true : a is not not defined

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

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

以下是来自AngularJS的一段代码:

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

他们的意图是根据请求动画帧中函数的可用性将rafSupport设置为true或false。

一般可以通过以下方式进行检查:

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

短的方法可以使用!!

rafSupported = !!requestAnimationFrame;

因此,如果请求动画帧被分配了一个函数,那么!请求动画帧将为false,并且它的另一个!将为true。

如果请求动画帧未定义,那么!请求动画帧将为true,另一个!将为false。

这么多的答案只完成了一半的工作。是的,!!X可以被解读为“X的真实性[表示为布尔值]”。但实际上,对于弄清楚单个变量是真是假(或者即使许多变量是真)来说,!!并不那么重要。!!myVar === truemyVar是一样的。将!!X与“真实”布尔值进行比较并不是真的有用。

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

简单铸造:(

那是…

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

上面的不是那么有用。if (!0)给出了与if (!!0 === false)相同的结果。我想不出一个好的例子来将变量转换为布尔值,然后与“真正的”布尔值进行比较。

请参阅“==和!=”从jslint的方向(注意:克罗克福德正在移动他的网站;该链接可能会在某些时候死亡),了解原因:

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

如果您只关心值是true还是false sy,请使用简写形式。而不是 (foo != 0)

就说 (foo)

而不是 (foo == 0)

(!foo)

请注意,在一些非直觉案例中,当将布尔值与数字进行比较时,布尔值将被转换为数字(true被转换为1false被转换为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());

因为一些历史悠久的Windows摇摆舞,这将在消息框中输出-1!在cmd.exe提示符中尝试一下!但是WScript.echo(-1 == test())仍然给你0,或者WScript的false看别处。太可怕了。

比较真实:)

但是,如果我有两个值需要检查相等的真伪呢?

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

  • myVar1 === myVar20 === undefined,显然是假的。
  • !!myVar1 === !!myVar2!!0 === !!undefined,是真的!同样的真实性!(在这种情况下,两者都“具有虚假的真实性”。)

因此,您真正需要使用“布尔转换变量”的唯一地方是,如果您正在检查两个变量是否具有相同真实性,对吧?也就是说,如果您需要查看两个变量是都为true还是都为false sy(或不是),即等于(或不是)true,请使用#0。

我想不出一个很好的、非人为的用例。也许您在表单中有“链接”字段?

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

即使在这种情况下,!!也是多余的。一个!就足以转换为布尔值,而你只是在检查相等性。


编辑24 Oct 2017,6 Feb 19:

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

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

React

例如,JSX(React)中的False具有特殊含义不是在简单的错误上触发的。如果您尝试在JSX中返回类似以下内容,期望messageCount中的int…

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

…当你有零条消息时,你可能会惊讶地看到React渲染0。你必须显式返回false才能让JSX不渲染。上面的语句返回0,JSX很乐意渲染它,因为它应该。它不能告诉你没有Count: {messageCount}

  • 一个解决方案涉及Bangang,它将0强制转换为!!0,即false{!!messageCount && <div>You have messages!</div>}

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

  • 我自己用三进制来处理虚假更舒服--{messageCount ? <div>You have messages!</div> : false}

TypeScript

TypeScript中的情况也是如此:如果你有一个返回布尔值的函数(或者你正在为布尔变量赋值),你[通常]不能返回/赋值布尔值;它必须是强类型的布尔值。这意味着,iff#0是强类型的return !myObject;适用于返回布尔值的函数,但return myObject;不适用。你必须return !!myObject(或以另一种方式转换为正确的布尔值)来匹配TypeScript的期望。

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

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

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

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

一元!运算符将其操作数转换为布尔值并对其进行否定。

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

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

!!xBoolean(x)的简写。

第一次爆炸强制JavaScript引擎运行Boolean(x),但它也有反转值的副作用。所以第二次爆炸取消了副作用。

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

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

  • 如果x是一个假值,!xtrue!!xfalse
  • 如果x是一个真值,!xfalse!!xtrue

当在布尔上下文的顶层(ifwhile?)使用时,!!运算符在行为上是一个no-op。例如,if (x)if (!!x)意味着同样的事情。

实际用途

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

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

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

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

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

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

我认为值得一提的是,与逻辑AND/OR组合的条件不会返回布尔值,而是在条件链的&&情况下返回最后一次成功或第一次失败,在||情况下返回第一次成功或最后一次失败。

res = (1 && 2); // res is 2res = (true && alert) // res is function alert()res = ('foo' || alert) // res is 'foo'

为了将条件转换为真正的布尔文字,我们可以使用双重否定:

res = !!(1 && 2); // res is trueres = !!(true && alert) // res is trueres = !!('foo' || alert) // res is true

使用逻辑非运算符两次。

它的意思是!true = false!!true = true

我只是想补充一下

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.foob.foo.bar
// This works -- these return undefined
a && a.foob.foo && b.foo.barb && b.foo && b.foo.bar

这里的技巧是&&链将返回它找到的第一个Falsey值-这可以被馈送到if语句等,因此如果b.foo未定义,它将返回未定义并跳过b.foo.bar语句,我们没有得到错误。

上面的返回未定义,但如果你有一个空字符串,false,null,0,untex,这些值将返回,一旦我们在链中遇到它们-[]{}都是“truthy”,我们将继续沿着所谓的“&&链”到右侧的下一个值。

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

因此,(b || {}).foob && b.foo相同,((b || {}).foo || {}).barb && b.foo && b.foo.bar相同。

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

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

!!类似于使用布尔构造函数,或者可以说更像布尔函数。

console.log(Boolean(null)); // Preferred over the Boolean object
console.log(new Boolean(null).valueOf()); // Not recommended for converting 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 falsy or truthy value of this.verticalconsole.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 falsy or truthy value of this.vertical which happens to be true anywayconsole.log(!!new Example(vertical).vertical); // Coerced value of this.vertical
vertical = -0; // Set vertical to -0, a falsy value.console.log(new Example(vertical).vertical); // The falsy or truthy value of this.vertical which happens to be false either wayconsole.log(!!new Example(vertical).vertical); // Coerced value of this.vertical

JavaScript胁迫虚假中的Falsy值,以及真实的价值观胁迫真的。中的Falsy和truthy值也可以在if语句中使用,并且基本上将“映射”到它们对应的布尔值。然而,您可能不会发现自己必须经常使用正确的布尔值,因为它们在输出(返回值)方面大多不同。

虽然这可能看起来类似于铸造,但实际上这可能是仅仅巧合,并且不是“构建”或故意为布尔型铸造而制作的。所以我们不要这样称呼它。


为什么以及如何工作

简而言之,它看起来像这样:! ( !null )。然而,nullFalsy,所以!null将是真正。然后!true将是虚假,它基本上是倒回,除了这次是null0(甚至null1和null2,如{}1)。


回到你的例子

总的来说,您看到的上下文只是根据是否定义了vertical来调整this.vertical,如果定义了;它将被设置为结果的垂直布尔值,否则不会改变。换句话说,如果定义了verticalthis.vertical将被设置为它的布尔值,否则,它将保持不变。我想这本身就是一个你将如何使用!!的例子,以及它的作用。


垂直I/O示例

运行此示例并摆弄输入中的垂直值。查看结果强制转换为什么,以便您可以完全理解上下文的代码。在输入中,输入任何有效的JavaScript值。

如果要测试字符串,请记住包含引号。不要太在意CSS和超文本标记语言代码,只需运行此代码段并使用它即可。但是,您可能需要查看与DOM无关的JavaScript代码(使用示例构造函数和垂直变量)。

var vertical = document.getElementById("vertical");var p = document.getElementById("result");
function Example(vertical){this.vertical = vertical !== undefined ? !!vertical :this.vertical;
return this.vertical;}
document.getElementById("run").onclick = function(){
p.innerHTML = !!(new Example(eval(vertical.value)).vertical);
}
input{text-align: center;width: 5em;}
button{margin: 15.5px;width: 14em;height: 3.4em;color: blue;}
var{color: purple;}
p {margin: 15px;}
span.comment {color: brown;}
<!--Vertical I/O Example--><h4>Vertical Example</h4><code id="code"><var class="var">var</var> vertical = <input type="text" id="vertical" maxlength="9" />; <span class="comment">//Enter any valid JavaScript value</span></code><br /><button id="run">Run</button><p id="result">...</p>

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

首先,您拥有的位置:

var zero = 0;

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

!zero; //true

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

基本上,!!确保我们得到的值是布尔值,而不是false sy、truthy、string等。

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

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

它返回变量的布尔值。

相反,可以使用Boolean类。

(请阅读代码说明。)

var X = "test"; // The X value is "test" as a String valuevar booleanX = !!X // booleanX is `true` as a Boolean value because non-empty strings evaluates as `true` in Booleanvar whatIsXValueInBoolean = Boolean(X) // whatIsXValueInBoolean is `true` againconsole.log(Boolean(X) === !!X) // Writes `true`

Boolean(X) = !!X在使用中。

请检查下面的代码片段

let a = 0console.log("a: ", a) // Writes a value in its kindconsole.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 `!!a`console.log("\n") // Newline
a = 1console.log("a: ", a)console.log("!a: ", !a)console.log("!!a: ", !!a) // Writes 1 value in Booleanconsole.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 Booleanconsole.log("\n") // Newline
a = "test"console.log("a: ", a) // Writes a value in its kindconsole.log("!a: ", !a)console.log("!!a: ", !!a) // Writes "test" value in Boolean
console.log("Boolean(a) === !!a: ", Boolean(a) === !!a) // writes true

它强制所有事物为布尔值。

例如:

console.log(undefined);   // -> undefinedconsole.log(!undefined);  // -> trueconsole.log(!!undefined); // -> false
console.log('abc');   // -> abcconsole.log(!'abc');  // -> falseconsole.log(!!'abc'); // -> true
console.log(0 === false);   // -> falseconsole.log(!0 === false);  // -> falseconsole.log(!!0 === false); // -> true

有时需要检查我们是否在函数中有一个值,数量本身对我们来说并不重要,但它是否重要。

例如,我们想检查用户是否有专业,我们有一个函数,就像:

hasMajor() {return this.major} // It returns "(users major is) Science"

但是答案对我们来说并不重要。我们只想检查它是否有一个主要的,我们需要一个布尔值(真或假)。我们如何得到它?

就像这样:

hasMajor() { return !(!this.major)}

或者是一样的

hasMajor() {return !!this.major)}

如果this.major有一个值,那么!this.major返回false,但因为该值有退出,我们需要返回true,我们使用!两次来返回正确的答案,!(!this.major)

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

因为JavaScript有所谓的“truthy”和“false sy”值,所以有些表达式在其他表达式中求值时会导致true或false条件,即使正在检查的值或表达式实际上不是truefalse

例如:

if (document.getElementById('myElement')) {// Code block}

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

但是:

if (document.getElementById('myElement') == true) {// Code block}

没有将导致一个true条件,并且代码块将不会被执行,即使元素确实存在。

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

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

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

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

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

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

要将您的JavaScript变量转换为Boolean,

var firstname = "test";// Type of firstname is string
var firstNameNotEmpty = !!firstname;// Type of firstNameNotEmpty is Boolean

JavaScript虚假用于""未定义null

对于不是空字符串{}[]新日期()以外的数字,JavaScript是真正,因此,

!!("test") /* Is true */!!("") /* Is false */

const foo = 'bar';console.log(!!foo); // Boolean: true

!否定(反转)一个值总是返回/产生一个布尔值。所以!'bar'会产生false(因为'bar'是truthy=>否定+Boolean=false)。使用额外的!运算符,值再次被否定,所以false变成true。

重要的是要记住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; // numbervar valueAsNegatedBoolean = !value; // boolean falsy (because 23 is truthy)var valueAsBoolean = !!value; // boolean truthyvar copyOfValue = value; // number 23
var value2 = 0;var value2AsNegatedBoolean = !value2; // boolean truthy (because 0 is falsy)var value2AsBoolean = !!value2; // boolean falsyvar copyOfValue2 = value2; // number 0
  • value2 = value;分配精确的对象value,即使它不是boolean,因此value2不一定最终是boolean
  • value2 = !!value;将保证的boolean赋值为操作数value的双重否定的结果,它等价于以下内容,但更短且可读:

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

!!不是操作符。它只是!操作符两次。

但是对于JavaScript,应用!!将Object转换为Boolean在大多数情况下是冗余和冗长的,因为:

任何值不是未定义或null的对象,包括值为false的布尔对象,在传递给条件语句

示例:if ({}) { console.log("{} is true")} // logs: "{} is true"

!!只是两次非运算符。净效果只是转换任何东西以确保布尔数据类型。例如。

!!未定义为false
!!0为false
!! null为false
!! anyObject为true
!! true是true
!! false就是false
!0为true
!1为false
!!”是假的

只是为了检查是否存在

if(!!isComplianceOnHold){//write code here is not undefined//if isComplianceOnHold is undefined or null will not enter in net is false// if isComplianceOnHold is not null or even boolean net result is true and enter inside if block}

任何值不为未定义或null的对象,包括值为false的布尔对象,在传递给条件语句时计算为true

这是我找到的最简单的答案:它的工作原理相当于Boolean(value)

你可以这样考虑!!

  1. 当第一个!应用时,变量变为布尔值,但具有相反的值
  2. 然后,第二个!只是恢复一个正义并将值恢复到其原始等价物