【问题标题】:Why (!+[]+[]) is 'true' and (false + []) is 'false' in Javascript?为什么 (!+[]+[]) 在 Javascript 中是 'true' 而 (false + []) 是 'false'?
【发布时间】:2019-01-14 20:53:40
【问题描述】:

我正在查看ECMA-262 语法以了解以下代码的定义:

const v = (! + [] + []);
const c = (false + []);

console.log(v);
console.log(c);

背后是什么?

直到现在我还没有发现任何有用的东西,有谁知道它为什么会给出这些结果或有关于它的参考资料?

【问题讨论】:

标签: javascript arrays ecmascript-6


【解决方案1】:

这是因为当您尝试将运算符应用于不同的数据结构时,JavaScript 引擎会应用 coercion

在第一种情况下,它的作用是:

  1. 将 first [] 转换为原始数据,这是通过调用数组的 toString() 方法来执行的。 toString 方法将所有数组值连接到一个字符串。如果你有类似(false + [1,2,3]) 的东西,你会得到:false1,2,3

  2. 第二步是将布尔值带入String上下文中

  3. 现在我们将所有值都放在同一个数据结构中,它将简单地连接所有值

在您的情况下,(! + [] + []) 被评估为长度为 4 的“真”。

You Don't Know JS: Types & Grammar 这本书是理解 JavaScript 引擎所做的所有这些奇怪操作的瑰宝。

编辑:正如 Felix Kling 所建议的那样!运算符在(! + [] + []) 的评估中扮演不同的角色。

在这种情况下会发生什么:

  • ! + [] 被评估为真。这是因为 ! + [] 将它们置于布尔上下文中,其中 [toNumber] 操作应用于 [] 即 0!0true

  • true + [] 被评估为'true'。这是因为当您尝试为对象添加布尔值(数组派生自对象)时,[toString] 操作将应用于这两个项目。

【讨论】:

  • FWIW,! + [1,2,3]true! 是一个运算符,而不是一个值。
  • @FelixKling 你说的第一句话是对的。至于另一个,一次!是在布尔上下文中引入的,我认为您可以从这个角度将其视为一个值。
  • “您可以从那个角度将其视为一个值” 不。运算符不是值,operate on 值。我只提到这一点是因为您的示例似乎暗示 ! 已转换为 false
  • 我觉得这个答案忽略了! 作用于一元返回的数字加上+[] 的观点,而是暗示! 本身可以用作一个值如果+ 是加法运算符,则为运算x + y。这不是发生的事情。第一行将是更多(! (+[])) + [],相当于!0 + []
【解决方案2】:

实际上,要了解为什么会得到该结果,您必须考虑如何评估表达式(即以什么顺序?)。如果我们观察你的第一个表情:

const v = (! + [] + []);

我们可以看到存在一个逻辑运算符(逻辑非!),一个一元运算符(+)和一个算术运算符,实际上是加法+。如果我们考虑到该表达式的求值顺序,我们可以这样写:

const v = ( (!(+[])) + [] );

现在,此处评估的第一个表达式是 +[],从 unary plus 运算符的文档中您可以得到:

一元加号运算符在其操作数之前并计算其操作数但尝试将其转换为数字,如果它还没有...

实际上,前面的评估结果为0(在将空数组强制转换为数字类型时会发生强制),您可以查看下一个示例:

console.log(+[]);

所以现在,表达式简化为

const v = ( (!0) + [] );

再次阅读您可以找到的logical not 运算符的一些文档:

如果其单个操作数可以转换为true,则返回false;否则,返回 true。

因此,!0 被简化为 true(另一个强制发生在数字零被强制转换为布尔类型的地方),您可以查看下一个示例:

console.log(!0);

现在,我们有了下一个表达式,addition 运算符发挥作用:

const v = ( true + [] );

加法运算符产生数字操作数或字符串连接的总和。

在这种情况下,运算符将进行字符串连接,因为操作数不是数字。所以,这里又出现了一个新的 coercion(基本上是隐式类型转换),因为它需要将两个操作数都转换为字符串:

  • 使用Boolean 类型的toString() 方法将true 转换为字符串"true"
  • 并且使用Array类型的可用toString()方法将空数组[]转换为空字符串""

最后,我们的表达式简化为:

const v = "true" + ""; // or simply "true".

const v = (! + [] + []);
console.log("value: " + v, "type: " + typeof(v));

第二个表达式现在应该很容易自己分析,因为它是第一个表达式的简化版本。

【讨论】:

    【解决方案3】:

    const v = (! + [] + []);
    const c = (false + []);
    
    console.log(v);
    console.log(c);

    如果你取出.length,你会看到结果是: truefalse 并且这些(+ 操作的结果)不是数组而是字符串,true 的长度为 4 个字符,false 的长度为 5。

    使用上面的链接,看起来这至少是部分相关的:

    12.7.3 The Addition operator ( + )

    注意加法运算符要么执行字符串连接,要么执行数字加法。

    【讨论】:

    • that these are not arrays but strings 是什么意思? [] 确实是数组,但是这些数组被转换为字符串。
    • @t.niese "these" 指的是v (true) 和c (false),而不是+ 的操作数。
    猜你喜欢
    • 2022-07-16
    • 1970-01-01
    • 2015-03-15
    • 2015-07-17
    • 2023-02-23
    • 1970-01-01
    • 1970-01-01
    • 2012-07-06
    相关资源
    最近更新 更多