我正在查看ECMA-262语法,以了解下一个代码的定义:
const v = (! + [] + []);
const c = (false + []);
console.log(v);
console.log(c);
这是什么?
直到现在我还没有发现任何有用的东西,有人知道为什么它会给出这些结果或对此有参考吗?
答案 0 :(得分:5)
这是因为当您尝试将运算符应用于其他数据结构时,JavaScript引擎将应用coercion。
第一种情况是:
将第一个[]转换为原始类型,这是通过调用array的toString()方法执行的。 toString方法将所有数组值连接到字符串。如果您希望使用(false + [1,2,3])
之类的东西,则会得到:false1,2,3
第二步是将布尔值带入String上下文
现在我们将所有值都放在相同的数据结构中,它将简单地将所有值连接起来
在您的情况下,(! + [] + [])
的值为'true',长度为4。
You Don't Know JS: Types & Grammar这本书是了解JavaScript引擎所做的所有这些奇怪操作的瑰宝。
编辑:正如Felix Kling所建议的那样!运算符在(! + [] + [])
的评估中起着不同的作用。
在这种情况下,发生的是:
! + []
的评估结果为true。这是因为! + []
将它们放在布尔上下文中,其中对0
和!0
为true
的[]应用 [toNumber] 操作
true + []
的评估结果为'true'
。这是因为当您尝试向对象添加布尔值(数组是从对象派生的)时, [toString] 操作将应用于这两个项目。
答案 1 :(得分:2)
const v = (! + [] + []);
const c = (false + []);
console.log(v);
console.log(c);
如果取出.length
,则会看到结果为:
true
和false
以及这些(+
操作的结果)不是数组而是字符串,并且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 + [] );
加法运算符产生数字操作数或字符串连接的总和。
在这种情况下,由于操作数不是数字,因此运算符将进行字符串连接。因此,在这里再次发生新的强制(基本上是类型的隐式转换),因为它需要将两个操作数都转换为字符串:
最后,我们的表达式简化为:
const v = "true" + ""; // or simply "true".
const v = (! + [] + []);
console.log("value: " + v, "type: " + typeof(v));
第二个表达式现在应该很容易自己分析,因为它是第一个表达式的简化版本。