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

Hex*_*ory 2906 javascript operators

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

我看到这个的背景是,

this.vertical = vertical !== undefined ? !!vertical : this.vertical;
Run Code Online (Sandbox Code Playgroud)

ste*_*ell 2583

强制oObject布尔值.如果它是falsey(例如,0, null,undefined等),这将是false,否则,true.

!oObject  //Inverted boolean
!!oObject //Non inverted boolean so true boolean representation
Run Code Online (Sandbox Code Playgroud)

所以!!不是运营商,只是!运营商两次.

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

let isIE8 = false;  
isIE8 = !! navigator.userAgent.match(/MSIE 8.0/);  
console.log(isIE8); // returns true or false 
Run Code Online (Sandbox Code Playgroud)

如果你⇒

console.log(navigator.userAgent.match(/MSIE 8.0/));  
// returns either an Array or null  
Run Code Online (Sandbox Code Playgroud)

但如果你⇒

console.log(!!navigator.userAgent.match(/MSIE 8.0/));  
// returns either true or false
Run Code Online (Sandbox Code Playgroud)

  • 它将非boolean转换为反向布尔值(例如,!5将为false,因为5是JS中的非假值),然后boolean-inverts,因此您将原始值作为布尔值(因此!! 5将是真的). (116认同)
  • 描述它的简单方法是:Boolean(5)=== !! 5; 相同的铸造,更少的字符. (104认同)
  • 这用于将truthy值转换为boolean true,而将falsy值转换为boolean false. (36认同)
  • @Micah Snyder要小心,在JavaScript中最好使用布尔基元,而不是使用新的布尔()来创建包含布尔值的对象.这是一个看到差异的例子:http://jsfiddle.net/eekbu/ (13认同)
  • 据我所知,这个bang-bang模式在if(... _语句)中没有用;只能在一个返回布尔值的函数的return语句中. (4认同)
  • @victorvartan 你的 [jsfiddle](http://jsfiddle.net/eekbu/) 使用 `new Boolean(5)`,但是如果你将其更改为仅使用 `Boolean(5)` 那么你的代码对两个变量都返回 true (4认同)
  • @sparkyShorts,如果您的代码使用`===`来比较布尔值,那么您必须使用`!!`键入强制转换"truthy"值到布尔值,否则您的结果将是错误的.例如,假设0表示false而1表示为true,那么`1 === true`将失败,而`!! 1 === true`正常工作. (3认同)
  • 这个 `Boolean(5) === !!5` 是不正确的:浏览器将评估为 `true`,但 `Boolean(5)` 返回一个 `Boolean` 对象,而 `!!5` 返回一个布尔文字。评估时,浏览器将用对象包装/解开文字,但 `typeof` 将返回第一个的 `'object'`,第二个的 `'boolean'`。 (2认同)
  • @Azder:我在Chrome,Firefox和IE8(在所有三个控制台中)都尝试了`typeof(Boolean(5))`和`typeof(!! 5)`并且它们都返回'boolean' (2认同)
  • @ Stevo3000 - 这不是错误的方法,只是不完整......'它将非布尔值转换为布尔值**并将其反转**,然后再将其反转****. (2认同)
  • @sparkyShorts 另一个例子:考虑对象 `obj.myString` 上的一个属性,它可以有一个字符串值,但也可以是一个空字符串、null 或未定义的。编写 `if (!!obj.myString) { doSomething() };` 比编写 `if (typeof obj.myString !== 'undefined' && obj.myString ! == null && obj.myString !== '') { doSomething() };` (2认同)

Tom*_*ter 827

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

!不是.所以!trueIS false,和!falsetrue.!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);
Run Code Online (Sandbox Code Playgroud)

  • `(userId == 0)?虚假:真实;"至少伤害我的大脑. (229认同)
  • "更容易理解"的变体在这里更容易理解吗?对0的检查不是对0的实际检查,而是检查Javascript认为等于0的有些奇怪的值列表.`userId?true:false`更清楚地说明正在进行转换并处理userId的值可能已显式设置为"undefined"的情况 (79认同)
  • !! false = false.!! true = true (66认同)
  • 我的大脑没有任何问题将`!! var`解码为`Boolean(var)`..并且`!!`更快(处理的指令更少)并且比替代方案更短. (50认同)
  • 我知道您多年前就写了这个答案,但为了今天对其进行完善:最容易理解的是 **说出您的意思**:`Boolean(x)`。我认为您的任何替代方案都不容易理解。更糟糕的是,至少在一种情况下,使用等式运算符“x != 0”会得到与“Boolean(x)”或“!!x”不同的结果:尝试使用“[]”来表示 x。另外,如果您确实喜欢使用相等运算符,为了获得其“真实性”规则,为什么不使用更明显的“(userId == true)”而不是“(userId != 0)”呢? (9认同)
  • 我不同意这一点.`userId!= 0`对于`null`,`NaN`和`undefined`是真的,但对于`false`则是false.如果你想要那种行为,你可能应该明确它.但即使它与`!! userId`完全相同,也不清楚你是否*想要*这些值在这里出现错误,或者你是否只是没有考虑Javascript的类型转换规则. (8认同)
  • @RickyClarkson主要是为了可读性,因为语法上它不是必需的.有些人使用总是在括号中包装条件的约定来将它与表达式的其余部分区分开来. (7认同)
  • 这比单弹操作员更难以理解? (6认同)
  • 值得注意的是,一些缩小器(例如Google的Closure Compiler)将`true`变成`!0`和`false`变成`!1`来保存字符(请注意,顺序看起来很笨拙但是正确,`!0 === true &&!1 === false`). (6认同)
  • `!!false` 是假的。`假!= 0` 为真。所以它们并不等同。`!!` 的有用目的是将*任何内容*强制为布尔值。 (5认同)
  • 值得注意的是,“!!”几乎可以移植到任何 C 风格语言 (4认同)
  • 对于未定义的伪值和NaN,x!= 0不会产生错误. (3认同)
  • 作为参考,布尔(x)和!!一样快!在当前的浏览器上(http://jsperf.com/boolean-conversion-speed).而且`a == b?true:false`与`(a == b)`:*相同,结果已经是布尔值*. (3认同)
  • 注意,那些代码并不完全等价.对于x = NaN !! x = False,x!= 0为True (3认同)
  • 如果你想要一个非模糊的转换为布尔值,使用`Boolean(x)`.在许多情况下,`x!= 0`是不可靠的. (3认同)
  • 在最后一个例子中,userId!= 0周围的()添加了什么? (2认同)
  • 显然这种默默无闻是值得的,因为它非常好地处理null.if(!! value)alert('value is not null')else alert('value is null')这个行为让我有兴趣查看它正在做的事情. (2认同)
  • "可怕的模糊"......"非常常见的惯用javascript用法"另请参阅各种评论指出x!= 0的缺陷 (2认同)
  • @cllpse你的意思是 !!false === false 和 !!true === true ?;-) (2认同)
  • @slim `false != 0` 实际上是 `false`。 (2认同)

Sal*_*n A 432

!!expr返回一个布尔值(truefalse),具体取决于表达式的真实性.在非布尔类型上使用时更有意义.考虑这些示例,尤其是第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!
Run Code Online (Sandbox Code Playgroud)

  • `new Boolean(false)`是一个对象,即使它包含一个伪值,一个对象也是真实的! (92认同)
  • 值得注意的是:`!! new Boolean(false)// true` (62认同)
  • ...还有`!! Boolean(false)// false` (42认同)
  • @SalmanA我也希望javascript有时候有意义:D (23认同)
  • @CamiloMartin:刚刚意识到`new Boolean(false)`返回一个`object`,而`Boolean(false)`返回_primitive_`false`.希望这是有道理的. (4认同)
  • 是的我知道,但考虑到大多数本机构造函数(`String`,`Number`,`Date`等)都可以作为函数调用的事实,但在这种情况下结果是不同的! (3认同)
  • 注意`[]`是真的,但是`[] == false`.因此,`!! [] == true`,但是`[] == false`. (2认同)

Ben*_*nny 146

泡一些茶:

!!不是运营商.它是两用的!- 这是逻辑"非"运算符.


理论上:

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

  • 事实是,这false不是true(这就是为什么会!false导致true)

  • 事实是,这true不是false(这就是为什么会!true导致false)


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

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

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


我们希望在比较中确定的是关于参考值的"真实性" ,而不是参考本身的.有一个用例我们可能想知道一个值的真相,即使我们期望值是false(或假的),或者我们期望值不是typeof boolean.


在实践中:

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

每个函数接受a <tag>和a 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
Run Code Online (Sandbox Code Playgroud)

我们离题了......

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

  • 完全很棒的答案,但我看不到它的实用性!!构造。由于 `if()` 语句已经将表达式转换为布尔值,因此将测试函数的返回值显式转换为布尔值是多余的 - 因为就 `if()` 语句而言,“真实性” === 真。或者我错过了一个场景,你需要一个真实的表达式来实际是布尔“true”? (6认同)
  • @TomAuger `if()` 语句确实针对 falsey 值转换了布尔值,但是如果你想在一个对象上实际设置一个布尔标志 - 它不会像 `if()` 语句那样转换它。例如`object.hasTheThing = !!castTheReturnValToBoolNoMatterWhat()` 将设置`true` 或`false` 而不是真正的返回值。另一个例子是可能所有管理员的“id”为“0”,而非管理员的“id”为“1”或更高。如果某人不是管理员,要获得“true”,您可以执行“person.isNotAdmin = !!admin.id”。用例很少,但有的时候很简洁。 (5认同)

Cre*_*esh 96

!!将其右侧的值转换为其等效的布尔值.(想想穷人的"打字"方式).它的目的通常是为了向用户传达的代码不关心读者什么是变量值,但什么是"真理"的值是.

  • 或者在右边的布尔值的情况下,它什么都不做. (4认同)
  • @Daniel:`!`仍然将值翻转到右边.在布尔值的情况下,最右边的`!`否定值,而最左边的`!`再次否定它.净效应是没有变化,但大多数引擎将生成双重否定的操作码. (3认同)

Chr*_*oph 68

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

您也可以使用与基本类型相对应的构造函数(使用new)来显式转换值,而不是这些黑客

Boolean(foo) === !!foo
Number(foo)  === +foo
String(foo)  === ''+foo
Run Code Online (Sandbox Code Playgroud)

  • 不,你不能:注意到构造函数在没有`new`的情况下被调用 - 正如我在答案中明确提到的那样 (13认同)
  • 太棒了!当你需要将"0"的字符串评估为false而不是true时,这对于一些小问题很有用.(即从选择中读取值时,因为它们被读作String).所以,如果你想把"0"视为负(布尔值假),假设`x ="0"`只需要:`x = !! + x; // false`与`Boolean(Number(x))相同`Number(或+ x)将字符串"0"转换为0,将其评估为false,然后将布尔(!! x)转换为boolean直接.十分简单! (2认同)
  • @DiegoDD你为什么选择`!! + x` vs`x!=="0"`? (2认同)

ruf*_*fin 63

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

你获得什么!!是检查多个变量的感实性的能力相互以可重复的,标准化的(和JSLint的友好)的方式.

简单铸造:(

那是...

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

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

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

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

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

说啊
(foo)

而不是
(foo == 0)


(!foo)

请注意,在将布尔值与数字进行比较时,有一些非直观的情况会将布尔值强制转换为数字(转换true1和转换false0).在这种情况下,!!可能在精神上有用.虽然,再次,这些是您将非布尔值与硬类型布尔值进行比较的情况,即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
?????????????????????????????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

根据你的引擎,事情变得更加疯狂.例如,WScript赢得了奖项.

function test()
{
    return (1 === 1);
}
WScript.echo(test());
Run Code Online (Sandbox Code Playgroud)

由于一些历史的Windows jive,它会在消息框中输出-1!在cmd.exe提示符下尝试,看看!但WScript.echo(-1 == test())仍然给你0或WScript false.把目光移开 这很可怕.

比较真实:)

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

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

  • myVar1 === myVar20 === undefined,显然是假的.
  • !!myVar1 === !!myVar2是的!!0 === !!undefined,是真的!同样诚实!(在这种情况下,两者都"有真实性".)

因此,你真正需要使用"boolean-cast变量"的唯一地方就是你要检查两个变量是否具有相同的真实性,对吧?也就是说,使用!!,如果您需要查看两个瓦尔是既truthy或两者falsy(或没有),也就是相等(或没有)感实性.

我无法想到一个伟大的,非人为的用例.也许你在表单中有"链接"字段?

if (!!customerInput.spouseName !== !!customerInput.spouseAge ) {
    errorObjects.spouse = "Please either enter a valid name AND age " 
        + "for your spouse or leave all spouse fields blank.";
}
Run Code Online (Sandbox Code Playgroud)

所以现在,如果您对配偶姓名和年龄都有两者或者一个假人,那么你可以继续.否则,您只有一个具有值的字段(或非常早期安排的婚姻)并且需要在您的errorObjects集合中创建额外的错误.


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

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

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

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

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

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

  • 一个补丁修复涉及棒棒,其胁迫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中的相同处理:如果你有一个返回布尔值的函数(或者你给一个布尔变量赋值),你[通常]不能返回/赋值一个布尔值y; 它必须是强类型布尔值.这意味着,iff myObject是强类型的,return !myObject;适用于返回布尔值的函数,但return myObject;不是.你必须要return !!myObject匹配Typescript的期望.

Typescript的例外?如果myObjectany,那么你回到JavaScript的Wild West并且可以在没有返回的情况下返回它!!,即使你的返回类型是布尔值.

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

但是如果你0在渲染的JSX中看到奇怪的东西,那就考虑松散的虚假管理.

  • 不,你不需要它.真实性和"真实""外部"在"if"中完全相同.我一直很努力,但我想不出一个理由,更喜欢铸造感实性为布尔值的那种错综复杂的外上方"比较truthinesses"的情况下,除了可读性如果以后重用的价值,作为'Q `库的例子.但即便如此,这也是一个信息损失的捷径,我认为你最好每次评估真实性. (2认同)

Gre*_*reg 52

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

true === !!10

false === !!0
Run Code Online (Sandbox Code Playgroud)

  • @Darren:他不是在比较类型; 他通过在答案中写断言来告诉你结果是什么. (42认同)
  • 为什么你会这样做?使用 !运算符转换为布尔值然后使用===来比较类型?只是接受你没有类型安全,并做val> 0或其他什么. (2认同)

Pau*_*lan 31

它将后缀转换为布尔值.


Bil*_*ard 25

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


Ste*_*son 22

似乎!!操作员导致双重否定.

var foo = "Hello World!";

!foo // Result: false
!!foo // Result: true
Run Code Online (Sandbox Code Playgroud)


Pra*_*ash 22

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


Ann*_*rom 19

!是"boolean not",它基本上将"enable"的值强制转换为其布尔相反的值.第二 !翻转此值.所以,!!enable意思是"不能启用",给你enable一个布尔值.


小智 17

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

res = (1 && 2); // res is 2
res = (true && alert) // res is function alert()
res = ('foo' || alert) // res is 'foo'
Run Code Online (Sandbox Code Playgroud)

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

res = !!(1 && 2); // res is true
res = !!(true && alert) // res is true
res = !!('foo' || alert) // res is true
Run Code Online (Sandbox Code Playgroud)


Nav*_*yar 14

!!构建体是转动任何JavaScript表达成其布尔等效的简单方式.

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

  • 非常接近重要的区别.**关键是`0 === false`为假,而'!! 0 === false`为真.** (2认同)

Jus*_*son 13

它不是一个单一的运营商,而是两个.它等同于以下内容,是一种将值转换为布尔值的快速方法.

val.enabled = !(!enable);
Run Code Online (Sandbox Code Playgroud)


Ali*_*eza 13

!!NOT一起使用两次操作,!将值转换为a boolean并将其反转,这是一个简单的例子,看看它是如何!!工作的:

首先,你有的地方:

var zero = 0;
Run Code Online (Sandbox Code Playgroud)

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

!zero; //true
Run Code Online (Sandbox Code Playgroud)

但我们不想要反转布尔值的值,所以我们可以再次反转它来得到我们的结果!这就是我们使用另一个的原因!.

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

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

var zero = 0;
!!zero; //false
Run Code Online (Sandbox Code Playgroud)


Dar*_*ark 9

我怀疑这是C++的遗留物,人们会覆盖它!运营商,但不是bool运营商.

因此,要获得负面(或肯定)答案,您首先需要使用!运算符得到一个布尔值,但如果你想检查肯定的情况会使用!!


Dam*_*ick 9

ifwhile报表,?操作者使用真值来决定执行其中的代码分支.例如,零和NaN数字以及空字符串为false,但其他数字和字符串为true.对象是真的,但未定义的值null都是假的.

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

  • 如果x是假值,!xtrue!!xfalse.
  • 如果x是真正的价值,!xfalse,!!xtrue.

当在布尔上下文的顶层中使用(if,while,或?),所述!!操作者是行为上无操作.例如,if (x)并且if (!!x)意思相同.

实际用途

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

一种用途是将对象有损压缩到其真值,这样您的代码就不会持有对大对象的引用并使其保持活动状态.分配!!some_big_object给变量而不是some_big_object让它去垃圾收集器.这对于生成对象或伪值(例如null未定义值)的情况(例如浏览器特征检测)非常有用.

我在回答有关C的相应!!操作符时提到的另一个用途是使用"lint"工具查找常见的拼写错误和打印诊断信息.例如,在C和JavaScript中,布尔运算的一些常见拼写错误会产生其输出不完全布尔的其他行为:

  • if (a = b)是任务,然后使用真值b; if (a == b)是一种平等比较.
  • if (a & b)是一个按位AND; if (a && b)是一个逻辑AND.2 & 50(假值); 2 && 5是真的.

!!运营商再次向皮棉工具,你写的是你的意思:做这个手术,然后取结果的真值.

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


Ser*_*sky 7

双布尔否定.通常用于检查值是否未定义.


小智 7

这里有很多很好的答案,但是如果你读到这么远,这有助于我"得到它".在Chrome(等)上打开控制台,然后输入:

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

当然,这些都只是键入!! someThing,但添加的括号可能有助于使其更容易理解.


Gre*_*Gum 7

!!x 是简写 Boolean(x)

第一次爆炸迫使js发动机运转,Boolean(x)但也有反转该值的副作用.所以第二次爆炸会解除副作用.


Wou*_*rck 6

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

public isAuthenticated(): boolean {
   return !!this.getToken();
}
Run Code Online (Sandbox Code Playgroud)


Khu*_*ong 6

它强制所有事物都布尔.

例如:

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
Run Code Online (Sandbox Code Playgroud)


小智 5

这是来自angular js的一段代码

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

 var rafSupported = !!requestAnimationFrame;
Run Code Online (Sandbox Code Playgroud)

他们的目的是根据 requestAnimationFrame 中函数的可用性将 rafSupported 设置为 true 或 false

一般可以通过以下方式检查来实现:

if(typeof  requestAnimationFrame === 'function')
rafSupported =true;
else
rafSupported =false;
Run Code Online (Sandbox Code Playgroud)

简短的方法可以使用!

rafSupported = !!requestAnimationFrame ;
Run Code Online (Sandbox Code Playgroud)

所以如果 requestAnimationFrame 被分配了一个函数,那么 !requestAnimationFrame 将是假的,还有一个!它会是真的

如果 requestAnimationFrame 未定义,则 !requestAnimationFrame 将是 true 并且还有一个!其中会是假的


Gib*_*boK 5

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

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

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

!!x // Same as Boolean(x). Note double exclamation mark
Run Code Online (Sandbox Code Playgroud)


Abh*_*xit 5

使用逻辑非运算符两次,
这意味着 !true = false !!true = true


Rya*_*lor 5

我只是想补充一点

if(variableThing){
  // do something
}
Run Code Online (Sandbox Code Playgroud)

是相同的

if(!!variableThing){
  // do something
}
Run Code Online (Sandbox Code Playgroud)

但是,当某些内容未定义时,这可能是个问题。

// 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
Run Code Online (Sandbox Code Playgroud)

这里的窍门是&&s 链将返回它找到的第一个false值 -并且可以将其馈送到if语句等。因此,如果b.foo是未定义的,它将返回undefined并跳过该b.foo.bar语句,而我们没有得到错误。

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

PS做同一件事的另一种方法是(b || {}).foo,因为如果b未定义,那么b || {}它将是{},并且您将访问空对象中的值(无错误),而不是尝试访问“ undefined”中的值(导致错误) )。因此,(b || {}).foob && b.foo((b || {}).foo || {}).bar相同b && b.foo && b.foo.bar


Mys*_*cal 5

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

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.vertical
console.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 anyway
console.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 way
console.log(!!new Example(vertical).vertical); // Coerced value of this.vertical
Run Code Online (Sandbox Code Playgroud)

JavaScript 中的Falsy 值强制false,而true 值 强制true 。假值和真值也可以在语句中使用if,并且本质上将“映射”到它们相应的布尔值。但是,您可能不会发现自己必须经常使用正确的布尔值,因为它们在输出(返回值)方面大多不同。

尽管这看起来与强制转换类似,但实际上这可能只是巧合,并不是为布尔强制转换而“构建”或专门制作的。所以我们不要这么称呼它。


为什么以及如何运作

简洁地说,它看起来像这样:! ( !null )。然而,null假的,所以!null真的。那么!true将为false,并且它本质上会反转回之前的状态,除了这次作为正确的布尔值(或者甚至反之亦然,对于 像或 这样的真值)。{}1


回到你的例子

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


垂直 I/O 示例

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

如果您正在测试字符串,请记住包含引号。不要太在意 CSS 和 HTML 代码,只需运行此代码片段并使用它即可。但是,您可能想看看与 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);

}
Run Code Online (Sandbox Code Playgroud)
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;
}
Run Code Online (Sandbox Code Playgroud)
<!--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>
Run Code Online (Sandbox Code Playgroud)


efk*_*kan 5

返回变量的布尔值。

相反,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`
Run Code Online (Sandbox Code Playgroud)

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

请检查下面的代码片段

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`
Run Code Online (Sandbox Code Playgroud)


Kir*_*ace 5

这个问题已经得到了很彻底的回答,但是我想补充一个我希望尽可能简化的答案,使之具有!!的含义!尽可能简单地掌握。

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

例如:

if (document.getElementById('myElement')) {
    // code block
}
Run Code Online (Sandbox Code Playgroud)

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

然而:

if (document.getElementById('myElement') == true) {
    // code block
}
Run Code Online (Sandbox Code Playgroud)

...将不会导致结果为真,即使该元素确实存在,也不会执行代码块。

为什么?因为document.getElementById()是一个“真实的”表达式,在该if()语句中其结果为true ,但不是的实际布尔值true

在这种情况下,双“ not”非常简单。not背对背仅两个秒。

第一个简单地“反转”真实值或falsey值,从而产生实际的布尔类型,然后第二个简单地将其“反转”回到其原始状态,但现在变为实际的布尔值。这样,您就可以保持一致性:

if (!!document.getElementById('myElement')) {}
Run Code Online (Sandbox Code Playgroud)

if (!!document.getElementById('myElement') == true) {}
Run Code Online (Sandbox Code Playgroud)

都将按预期返回true。


Luc*_*ain 5

记住对JavaScripttruefalseJavaScript 中的评估很重要:

  • 具有“值”的所有内容都是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
Run Code Online (Sandbox Code Playgroud)
  • value2 = value;分配确切的对象,value即使它不是,boolean因此value2不一定最终是boolean.
  • value2 = !!value;分配一个保证boolean作为操作数的双重否定的结果,value它等效于以下但更短且可读:

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
Run Code Online (Sandbox Code Playgroud)