为什么Javascript中的(!+ [] + [])为'true'和(false + [])为'false'?

时间:2019-01-14 20:53:40

标签: javascript arrays ecmascript-6

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

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

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

这是什么?

直到现在我还没有发现任何有用的东西,有人知道为什么它会给出这些结果或对此有参考吗?

3 个答案:

答案 0 :(得分:5)

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

第一种情况是:

  1. 将第一个[]转换为原始类型,这是通过调用array的toString()方法执行的。 toString方法将所有数组值连接到字符串。如果您希望使用(false + [1,2,3])之类的东西,则会得到:false1,2,3

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

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

在您的情况下,(! + [] + [])的值为'true',长度为4。

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

编辑:正如Felix Kling所建议的那样!运算符在(! + [] + [])的评估中起着不同的作用。

在这种情况下,发生的是:

  • ! + []的评估结果为true。这是因为! + []将它们放在布尔上下文中,其中对0!0true的[]应用 [toNumber] 操作

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

答案 1 :(得分:2)

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

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

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

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

12.7.3 The Addition operator ( + )

  

注意加法运算符可以执行字符串连接或数字加法。

答案 2 :(得分:2)

实际上,为了理解为什么会得到该结果,您必须考虑如何对表达式求值(即以什么顺序进行)。如果我们观察到您的第一个表情:

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

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

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

现在,这里计算的第一个表达式是+[],从unary plus运算符的文档中您将获得:

  

一元加号运算符位于其操作数之前,并求值为其操作数,但是如果尚未将其转换为数字,则会尝试将其转换为数字。

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

console.log(+[]);

所以现在,表达式简化为

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

再次阅读该logical not运算符的一些文档,您会发现:

  

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

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

console.log(!0);

现在,我们有了下一个表达式,其中addition运算符开始起作用:

const v = ( true + [] );
  

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

在这种情况下,由于操作数不是数字,因此运算符将进行字符串连接。因此,在这里再次发生新的强制(基本上是类型的隐式转换),因为它需要将两个操作数都转换为字符串:

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

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

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

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

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