ChatGPT解决这个技术问题 Extra ChatGPT

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

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

我看到这个的背景是,

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 年里,我总是在心里幽默地说“砰砰!你是布尔型的!”在反转布尔值时,我一直记得结果如何。我决定今天查看您的评论并让您知道:-)

m
mikemaccana

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

!object  // inverted boolean
!!object // non inverted 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

它将非布尔值转换为反转布尔值(例如,!5 为假,因为 5 在 JS 中是非假值),然后布尔反转,因此您将原始值作为布尔值(所以 !!5 将是真的)。
一个简单的描述方法是: Boolean(5) === !!5;相同的演员阵容,更少的角色。
这用于将真值转换为布尔真,而假值太布尔假。
@Micah Snyder 请注意,在 JavaScript 中,最好使用布尔原语,而不是使用 new Boolean() 创建将布尔值框起来的对象。下面是一个示例,可以看出差异:jsfiddle.net/eekbu
据我所知,这种 bang-bang 模式在 if(..._ 语句中没有用;仅在应该返回布尔值的函数的 return 语句中。
m
mikemaccana

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

! 表示。所以 !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 just
val.enabled = Boolean(userId);

注意:后两个表达式在某些极端情况(例如,当 userId[] 时)并不完全等同于第一个表达式,因为 {3 } 运算符有效,什么值被认为是 truthy


!!假=假。 !!真=真
“更容易理解”的变体在这里真的更容易理解吗?对 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) 呢?
S
Salman A

!!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() 将表达式的值强制为原始布尔值)。
B
Benny Schmidt

泡茶:

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

理论上:

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

事实是假不是真的(这就是为什么!假结果为真)

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

!! 确定一个值的“真相”not not:

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

事实是假不是不假(这就是为什么!!假导致假)

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

每个函数都接受要查找的 <tag>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() 语句已经将表达式转换为布尔值,因此将测试函数的返回值显式转换为布尔值是多余的 - 因为无论如何“真实性” === true 就 if() 语句而言。还是我错过了一个你需要一个真实的表达式才能真正成为布尔 true 的场景?
@TomAuger if() 语句确实针对虚假值强制转换布尔值,但是说您想在对象上实际设置一个布尔标志 - 它不会像 if() 语句那样强制转换它。例如 object.hasTheThing = !!castTheReturnValToBoolNoMatterWhat() 将设置 truefalse 而不是真正的返回值。另一个示例可能是所有管理员都是 0id,而非管理员的 id 为 1 或更高。如果某人不是管理员,要获得 true,您可以执行 person.isNotAdmin = !!admin.id。用例很少,但有的时候很简洁。
C
Crescent Fresh

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


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

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

除了这些技巧,您还可以使用与原始类型对应的构造函数(without using 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 因为例如您可能希望转换该值并将其分配给其他变量,无论您是否要将其与其他变量进行比较。
r
ruffin

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

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

简单地铸造:(

那是...

0 === 假是假的。

!!0 === 假是真的。

上面的用处不大。 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 的 falseLook away. It's hideous.

比较真实性:)

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

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

myVar1 === myVar2 为 0 === 未定义,显然是错误的。

!!myVar1 === !!myVar2 是 !!0 === !!undefined 并且是真的!一样的真实! (在这种情况下,两者都“具有虚假的真实性”。)

因此,您真正需要使用“布尔转换变量”的唯一地方是,您需要检查两个变量是否具有 same 真实性,对吗?也就是说,如果您需要查看两个变量是否都为真或都为假(或不是),则使用!!,即相等(或不)真实性

我想不出一个伟大的、非人为的用例来做这个副手。也许您在表单中有“链接”字段?

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 方库

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

反应

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

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

...当您的消息为零时,您可能会惊讶地看到 React 呈现 0。您必须显式返回 false 才能使 JSX 不呈现。上面的语句返回 0,JSX 会按照它应该的方式愉快地渲染它。它不能告诉您没有 Count: {messageCount}

一种修复方法是使用 bangbang,它将 0 强制转换为 !!0,这是错误的:{!!messageCount &&

You have messages!
}

JSX 的文档建议您更加明确,编写自注释代码,并使用比较来强制为布尔值。 {messageCount > 0 &&

你有消息!
}

我更愿意自己用三元处理虚假 - {messageCount ?

你有消息!
: false}

打字稿

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

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

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

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


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

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

true === !!10

false === !!0

P
Paul McMillan

它将后缀转换为布尔值。


B
Bill the Lizard

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


L
Lightness Races in Orbit

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

var foo = "Hello World!";

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

P
Prakash

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


A
Alireza

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

首先,你有的地方:

var zero = 0;

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

!zero; //true

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

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

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

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

A
Annika Backstrom

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


G
GreQ

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

S
Sebastian Simon

!! 构造是一种将任何 JavaScript 表达式转换为其等效布尔值的简单方法。

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


非常接近重要的区别。 关键是 0 === false 为假,!!0 === false 为真。
J
Justin Johnson

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

val.enabled = !(!enable);

K
KWallace

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

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

例如:

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

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

然而:

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

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

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

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

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

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

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

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


D
Darren Clark

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

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


D
Damian Yerrick

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

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

如果 x 为假值,则 !x 为真,而 !!x 为假。

如果 x 为真值,!x 为假,!!x 为真。

在布尔上下文(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 & b) 是按位与; if (a && b) 是逻辑与。 2 & 5 为 0(假值); 2 && 5 为真。

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

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


S
Sergey Ilinsky

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


R
Ryan Taylor

我只是想补充一点

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

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

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

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

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


好点 - 改变了我的答案。它仅在嵌套三层深度的对象上发生,因为就像您说的 ({}).anything 会给 undefined
G
Greg Gum

!!xBoolean(x) 的简写

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


S
Sathyam Lokare

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

例如:

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

W
Warren Davis

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

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

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


W
Wouter Vanherck

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

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

J
JeevanReddy Avanaganti

这是来自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 将是 false 并且还有一个!这将是真的

如果 requestAnimationFrame 是未定义的,那么 !requestAnimationFrame 将是真的,而且还有一个!这将是错误的


e
efkan

返回变量的布尔值。

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

请查看下面的代码片段↓

let a = 0 console.log("a: ", a) // 将值写入其类型 console.log("!a: ", !a) // 将 '0 is NOT true in boolean' 写入 boolean - 这是真的。在布尔值中,0 表示假,1 表示真。 console.log("!!a: ", !!a) // 在布尔值中写入 0 值。 0 表示错误。 console.log("Boolean(a): ", Boolean(a)) // 等于 `!!a` console.log("\n") // 换行 a = 1 console.log("a: ", a) console.log("!a: ", !a) console.log("!!a: ", !!a) // 在布尔值中写入 1 个值 console.log("\n") // 换行 a = "" console.log("a: ", a) console.log("!a: ", !a) // 写 '"" is NOT true in boolean' value as boolean - 所以这是真的。在 boolean empty字符串、空值和未定义值表示假,如果有字符串则表示真。 console.log("!!a: ", !!a) // 将 "" 值写入布尔值 console.log("\n") // 换行 a = "test" console.log("a: ", a ) // 在其类型中写入一个值 console.log("!a: ", !a) console.log("!!a: ", !!a) // 在布尔值中写入“测试”值 console.log( "Boolean(a) === !!a: ", Boolean(a) === !!a) // 写成 true


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

使用逻辑非运算符两次
表示 !true = false !!true = true


L
Lucky Brain

请务必记住 JavaScript 中对 truefalse 的计算:

带有“值”的所有内容都是真的(即真),例如:101、3.1415、-11、“幸运脑”、new Object(),当然还有真的

101,

3.1415,

-11,

“幸运大脑”,

新对象()

而且,当然,真的

没有“值”的所有内容都是假的(即假的),例如:0、-0、“”(空字符串)、未定义、空、NaN(不是数字),当然还有假

0,

-0,

"" (空字符串),

不明确的,

无效的,

NaN(不是数字)

当然,错误的

应用“logical not”运算符 (!) 计算操作数,将其转换为 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

价值2 =价值;分配确切的对象值,即使它不是布尔值,因此 value2 不一定最终是布尔值。

价值2 = !!价值;作为操作数值的双重否定的结果,分配一个有保证的布尔值,它等价于以下但更短且可读性:

如果(值){ value2 = true; } 其他 { value2 = false; }


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