Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Addition on two blank objects or blank arrays in javascript [duplicate]

I was just playing around with javascript when i found the following console outputs:

  1. [] + [] // output: ""
  2. [] + {} // output: [object Object]
  3. {} + [] // output: 0
  4. {} + {} // output: 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.

like image 756
invincibleDudess Avatar asked May 11 '15 11:05

invincibleDudess


1 Answers

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):

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.

{} + [] // 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]".

Unexpected results

Things get weird if the first operand of + is an empty object literal (results as seen on the Firefox console):

{} + {}//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:

+"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:

{} + {}//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.

References

What is {} + {} in JavaScript?

like image 94
Alex Char Avatar answered Oct 27 '22 23:10

Alex Char