This question already has an answer here:
这个问题在这里已有答案:
- What is the explanation for these bizarre JavaScript behaviours mentioned in the 'Wat' talk for CodeMash 2012? 5 answers
对于CodeMash 2012的“Wat”演讲中提到的这些奇怪的JavaScript行为有什么解释? 5个答案
I was just playing around with javascript when i found the following console outputs:
当我找到以下控制台输出时,我只是在玩javascript:
[] + []
// output: ""[] + [] //输出:“”
[] + {}
// output: [object Object][] + {} //输出:[object Object]
{} + []
// output: 0{} + [] //输出:0
{} + {}
// output: NaN{} + {} //输出:NaN
Could anyone please explain me the logic behind these output. I feel its a very strange behaviour but i guess maybe it has some logic.
有谁能请解释这些输出背后的逻辑。我觉得这是一个非常奇怪的行为,但我猜它可能有一些逻辑。
Thanks in advance.
提前致谢。
1 个解决方案
#1
Expected results
When you are adding two arrays, everything works as expected:
当您添加两个数组时,一切都按预期工作:
[] + []//output''
Converting []
to a primitive first tries valueOf()
which returns the array itself (this
):
首先将[]转换为原语会尝试返回数组本身的valueOf()(this):
var arr = [];
arr.valueOf() === arr
true
As that result is not a primitive, toString() is called next and returns the empty string (which is a primitive). Therefore, the result of [] + []
is the concatenation of two empty strings.
由于该结果不是原语,因此将调用toString()并返回空字符串(这是一个原语)。因此,[] + []的结果是两个空字符串的串联。
{} + [] // output: 0
Adding an array and an object also conforms to our expectations:
添加数组和对象也符合我们的期望:
[] + {}//output '[object Object]'
Explanation: converting an empty object to string yields the following result.
说明:将空对象转换为字符串会产生以下结果。
String({})//output: '[object Object]'
The previous result is thus created by concatenating ""
and "[object Object]"
.
因此,通过连接“”和“[object Object]”来创建先前的结果。
Unexpected results
Things get weird if the first operand of + is an empty object literal (results as seen on the Firefox console):
如果+的第一个操作数是一个空的对象文字(在Firefox控制台上看到的结果),事情会变得奇怪:
{} + {}//output: NaN
What is going on here? The problem is that JavaScript interprets the first {}
as an empty code block and ignores it. The NaN
is therefore computed by evaluating +{}
(plus followed by the second {}
). The plus you see here is not the binary addition operator, but a unary prefix operator that converts its operand to a number, in the same manner as Number()
. For example:
这里发生了什么?问题是JavaScript将第一个{}解释为空代码块并忽略它。因此,通过评估+ {}(加上后跟第二个{})来计算NaN。你在这里看到的加号不是二元加法运算符,而是一个一元前缀运算符,它将其操作数转换为数字,方法与Number()相同。例如:
+"3.65"
3.65
The following expressions are all equivalent:
以下表达式都是等效的:
+{}
Number({})
Number({}.toString()) // {}.valueOf() isn’t primitive
Number("[object Object]")
NaN
Why is the first {}
interpreted as a code block? Because the complete input is parsed as a statement and curly braces at the beginning of a statement are interpreted as starting a code block. Hence, you can fix things by forcing the input to be parsed as an expression:
为什么第一个{}被解释为代码块?因为完整的输入被解析为语句,并且语句开头的花括号被解释为启动代码块。因此,您可以通过强制将输入解析为表达式来修复问题:
({} + {})//output: '[object Object][object Object]'
Arguments of functions or methods are also always parsed as expressions:
函数或方法的参数也总是被解析为表达式:
console.log({} + {})//output: [object Object][object Object]
After the previous explanations, you should not be surprised about the following result, any more:
在前面的解释之后,您不应该对以下结果感到惊讶:
{} + []//output: 0
Again, this is interpreted as a code block followed by +[]
. The following expressions are equivalent:
同样,这被解释为代码块后跟+ []。以下表达式是等效的:
+[]
Number([])
Number([].toString()) // [].valueOf() isn’t primitive
Number("")
0
Interestingly, the Node.js REPL parses its input differently from either Firefox or Chrome (which even uses the same V8 JavaScript engine as Node.js). The following input is parsed as expressions and the results are less surprising:
有趣的是,Node.js REPL以不同于Firefox或Chrome的方式解析其输入(甚至使用与Node.js相同的V8 JavaScript引擎)。以下输入被解析为表达式,结果不那么令人惊讶:
{} + {}//output: '[object Object][object Object]'
{} + []//output '[object Object]'
This has the advantage of being more like the results you get when using the input as arguments of console.log(). But it is also less like using the input as statements in programs.
这样做的好处是更像是将输入用作console.log()的参数时得到的结果。但它也不像在程序中使用输入作为语句。
References
What is {} + {} in JavaScript?
JavaScript中的{} + {}是什么?
#1
Expected results
When you are adding two arrays, everything works as expected:
当您添加两个数组时,一切都按预期工作:
[] + []//output''
Converting []
to a primitive first tries valueOf()
which returns the array itself (this
):
首先将[]转换为原语会尝试返回数组本身的valueOf()(this):
var arr = [];
arr.valueOf() === arr
true
As that result is not a primitive, toString() is called next and returns the empty string (which is a primitive). Therefore, the result of [] + []
is the concatenation of two empty strings.
由于该结果不是原语,因此将调用toString()并返回空字符串(这是一个原语)。因此,[] + []的结果是两个空字符串的串联。
{} + [] // output: 0
Adding an array and an object also conforms to our expectations:
添加数组和对象也符合我们的期望:
[] + {}//output '[object Object]'
Explanation: converting an empty object to string yields the following result.
说明:将空对象转换为字符串会产生以下结果。
String({})//output: '[object Object]'
The previous result is thus created by concatenating ""
and "[object Object]"
.
因此,通过连接“”和“[object Object]”来创建先前的结果。
Unexpected results
Things get weird if the first operand of + is an empty object literal (results as seen on the Firefox console):
如果+的第一个操作数是一个空的对象文字(在Firefox控制台上看到的结果),事情会变得奇怪:
{} + {}//output: NaN
What is going on here? The problem is that JavaScript interprets the first {}
as an empty code block and ignores it. The NaN
is therefore computed by evaluating +{}
(plus followed by the second {}
). The plus you see here is not the binary addition operator, but a unary prefix operator that converts its operand to a number, in the same manner as Number()
. For example:
这里发生了什么?问题是JavaScript将第一个{}解释为空代码块并忽略它。因此,通过评估+ {}(加上后跟第二个{})来计算NaN。你在这里看到的加号不是二元加法运算符,而是一个一元前缀运算符,它将其操作数转换为数字,方法与Number()相同。例如:
+"3.65"
3.65
The following expressions are all equivalent:
以下表达式都是等效的:
+{}
Number({})
Number({}.toString()) // {}.valueOf() isn’t primitive
Number("[object Object]")
NaN
Why is the first {}
interpreted as a code block? Because the complete input is parsed as a statement and curly braces at the beginning of a statement are interpreted as starting a code block. Hence, you can fix things by forcing the input to be parsed as an expression:
为什么第一个{}被解释为代码块?因为完整的输入被解析为语句,并且语句开头的花括号被解释为启动代码块。因此,您可以通过强制将输入解析为表达式来修复问题:
({} + {})//output: '[object Object][object Object]'
Arguments of functions or methods are also always parsed as expressions:
函数或方法的参数也总是被解析为表达式:
console.log({} + {})//output: [object Object][object Object]
After the previous explanations, you should not be surprised about the following result, any more:
在前面的解释之后,您不应该对以下结果感到惊讶:
{} + []//output: 0
Again, this is interpreted as a code block followed by +[]
. The following expressions are equivalent:
同样,这被解释为代码块后跟+ []。以下表达式是等效的:
+[]
Number([])
Number([].toString()) // [].valueOf() isn’t primitive
Number("")
0
Interestingly, the Node.js REPL parses its input differently from either Firefox or Chrome (which even uses the same V8 JavaScript engine as Node.js). The following input is parsed as expressions and the results are less surprising:
有趣的是,Node.js REPL以不同于Firefox或Chrome的方式解析其输入(甚至使用与Node.js相同的V8 JavaScript引擎)。以下输入被解析为表达式,结果不那么令人惊讶:
{} + {}//output: '[object Object][object Object]'
{} + []//output '[object Object]'
This has the advantage of being more like the results you get when using the input as arguments of console.log(). But it is also less like using the input as statements in programs.
这样做的好处是更像是将输入用作console.log()的参数时得到的结果。但它也不像在程序中使用输入作为语句。
References
What is {} + {} in JavaScript?
JavaScript中的{} + {}是什么?