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

我看到这件事的背景是,

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

当前回答

简单地说!!只返回一个布尔值,如果对象不是null或undefined,则返回true,否则返回false。

你可以这么说!!object等于if(object)返回true,否则返回false。

就这么简单!

其他回答

这是一次双重手术。第一个!将值转换为布尔值并反转其逻辑值。第二个!反转逻辑值。

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

双重否定运算符!!计算值的真值。实际上是两个操作员,哪里!!x表示!(!x),并且行为如下:

如果x为假值!x为真,并且!!x为假。如果x是真值!x为假,并且!!x为真。

当在布尔上下文的顶层使用时(if、while或?)!!从行为上讲,操作员是一个no-op。例如,if(x)和if(!!x)表示相同的意思。

实际用途

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

一种用法是将对象压缩到其真值,这样代码就不会保存对大对象的引用并保持其活动。分配!!some_big_object设置为变量,而不是some_biguobject让垃圾收集器使用它。这对于生成对象或假值(例如空值或未定义值)的情况非常有用,例如浏览器特征检测。

另一个用法,我在一个关于C对应的答案中提到了!!操作员使用“lint”工具查找常见的打字错误和打印诊断。例如,在C和JavaScript中,布尔运算的一些常见错误会产生其他输出不太布尔的行为:

如果(a=b)是赋值,然后使用b的真值;如果(a==b)是相等比较。如果(a&b)是位AND;如果(a&&b)是逻辑AND。2和5为0(假值);2&&5为真。

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

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

看来是!!运算符导致双重否定。

var foo = "Hello, World!";

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

这么多答案做了一半的工作。对X可以理解为“X的真实性[表示为布尔值]”。但是实际上,对于弄清楚一个变量是真是假(或者即使很多变量都是真的)来说,不是那么重要!!myVar==true与myVar相同。比较!!将X转换为“真实”布尔值并不是很有用。

你唯一的收获!!是以可重复、标准化(和JSLint友好)的方式检查多个变量之间的真实性的能力。

简单铸造:(

那就是。。。

0===false为false。!!0===假为真。

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

请参阅JSLint的指示中的“==and!=”(注意:Crockford正在移动他的站点;该链接可能会在某一点上失效),了解原因:

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

注意,在将布尔值与数字进行比较时,有一些不直观的情况,布尔值将被转换为数字(true被转换为1,false被转换为0)。在这种情况下!!可能在精神上有用。不过,在这些情况下,您将非布尔值与硬类型布尔值进行比较,在我看来,这是一个严重的错误。如果(-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。移开视线。这太可怕了。

比较真实性:)

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

假设我们有myVar1=0;并且myVar2=undefined;。

myVar1==myVar2为0==未定义,显然为假。!!myVar1==!!myVar2是!!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集合中创建一个额外的错误。

尽管即使在这种情况下!!真的是多余的。一足以转换为布尔值,而您只是在检查是否相等。


编辑:2017年10月24日,2月19日:

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

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

反应

例如,JSX(React)中的False有一个特殊的含义,它不会在简单的错误中触发。如果您尝试在JSX中返回以下内容,则messageCount中应为int。。。

{messageCount&&<div>您有消息!</div>}

…当您没有消息时,您可能会惊讶地看到React呈现0。您必须显式返回false,以便JSX不呈现。上面的语句返回0,JSX很高兴地将其呈现出来。它不能告诉你没有计数:{messageCount}。

一个修复方法涉及bangbang,它将0强制为!!0,这是错误的:{!!messageCount&&<div>您有消息!</div>}JSX的文档建议您更加明确,编写自我注释代码,并使用比较强制转换为布尔值。{messageCount>0&&<div>您有消息!</div>}我自己用三元表处理错误更舒服--{messageCount?<div>您有消息!</div>:false}

TypeScript(类型脚本)

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

TypeScript的例外?如果myObject是any,那么您将返回JavaScript的Wild West,并且可以不使用!!,即使您的返回类型是布尔值。

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

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

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

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

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

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