38

If you open your JS console and type in [] + {} === {} + [] it tells you it's true.

I don't understand why this is. I attempted to look up at how it's parsed.

For [] + {} the + here is the addition operator as operands are both literals. LHS doesn't yield a number through .valueOf() so it performs string concatenation using .toString() on both operands giving us "" + "[object Object]"

For {} + [] the {} is an empty code block and is 'ignored', the + operator here is parsed as the unary plus operator, it converts its operand to a Number. Empty arrays converted to a number become 0

So this is appears to be "[object Object]" === 0 which surely should be false?.

The identity operator checks if the two operands are equal without type conversion. I can't see how this ever coud be true. What part of the story am I missing?

Edit:

I see if you type ({} + []) it parses it as an empty object making the RHS equal to "[object Object]". I looked this up and ( ) is the grouping operator. So perhaps this has something to do with this?

This is not a duplicate of What is the explanation for these bizarre JavaScript behaviours mentioned in the 'Wat' talk for CodeMash 2012?. Answer bullet points 1 === 2 should NOT be true.

Malekai
  • 4,765
  • 5
  • 25
  • 60
Mardoxx
  • 4,372
  • 7
  • 41
  • 67
  • 5
    http://stackoverflow.com/questions/9032856/what-is-the-explanation-for-these-bizarre-javascript-behaviours-mentioned-in-the And http://stackoverflow.com/questions/36438034/why-is-no-longer-nan-in-chrome-console – epascarello Dec 13 '16 at 15:07
  • Empty object parameters return an object constructor also == `true` and an empty array is also a constructor object which return true – Dennisrec Dec 13 '16 at 15:07
  • 12
    `{}` can't possibly be interpreted as an empty block, since it comes immediately after `===` (and `[] + {} ===` is not a valid statement in itself). – Frxstrem Dec 13 '16 at 15:09
  • Ah good point. so RHS would evaluate to empty object + array. So both sides would equate to "object Object" so statement in question would be true. Cool, thanks. – Mardoxx Dec 13 '16 at 15:11
  • 1
    Not really a WTF, just misunderstanding of the interpreter! :) – Mardoxx Dec 13 '16 at 15:13
  • 3
    `([] + {}) === ({} + [])` is true too – vinczemarton Dec 13 '16 at 15:13
  • http://www.2ality.com/2012/01/object-plus-object.html – philantrovert Dec 13 '16 at 15:14
  • 6
    It's point 2 of the "not a duplicate". It exactly explains what happens `[] + {}` evaluates to `"[object Object]"` - the _string_, and then `{} + []` does the exact same thing. The fact that it looks like point 3 in the other question is irrelevant, because the driving thing there is `{}` being the _first_ thing on the line - that makes it be an empty block. In this case, it's exactly equivalent to `{} + []` as it produces `"[object Object]"`. – VLAZ Dec 13 '16 at 15:19
  • Hmm okay, so why then does `{} + [] === [] + {}` LHS should be 0 as first thing on line makes it empty block, RHS is "[object Object]"? – Mardoxx Dec 13 '16 at 15:23
  • "So this is appears to be "[object Object]" === 0 which surely shouldn't be false?." Don't you mean "shouldn't be true" or "should be false", or did I completely misunderstand the question? – Dark Hippo Dec 13 '16 at 15:28
  • @SoonDead http://i.stack.imgur.com/SILP9.png take _that_, strict equality! – Mike G Dec 13 '16 at 20:10

2 Answers2

54

The second point in this magnificent answer explains what happens when you "add together" an array and an object.

var result = [] + {};

console.log(result);
console.log(typeof result);

What you get is the string [object Object] because each of the arguments is converted to a string. For an array, that results in calling .join() on it, which in turn, results in an empty string. For Objects, it produces the string "[object Object]" - adding them together leaves the second string.

The same happens on both sides of the comparison - on the right hand side, the order is different but that does not matter. The result will not be the same as point 3 in the answer, for the difference is that there {} + [] is in the beginning of the line, so {} is interpreted as an empty block. In this situation it will (correctly) be interpreted as a plain object notation). The same casting logic will be performed and it will produce the same string as before: "[object Object]"

So, in the end, you are comparing "[object Object]" === "[object Object]" which returns true.

Note that {} + [] === [] + {} will not produce the same - again, due to point 3 of the linked answer - the first {} will be interpreted as an empty block, so the left hand side becomes +[] which converts the array to a number, hence the result of the comparison will be false. However if you test this expression in the Chrome dev tools you will indeed get true. This is because Chrome will auto-wrap your expression in parentheses which forces the initial {} to be interpreted as an object. Checking {} + [] === [] + {} in Firefox or Node REPL or others should produce the "correct" false.

Community
  • 1
  • 1
VLAZ
  • 26,331
  • 9
  • 49
  • 67
  • I cannot figure out the formatting on this. But, Node says you're wrong about that. `> {} + [] 0 > [] + {} '[object Object]' > {} + [] === [] + {} true >` – Eric Blade Jun 24 '18 at 14:51
  • @EricBlade hmm, interesting. I cannot replicate it, but it might be something to do with the NodeJS installation. That's certainly how it worked back when I wrote that answer and since I don't have it installed right now, I used [this online REPL service](https://repl.it/languages/Nodejs) which is running v9.7.1 and does return `false` for `{} + [] === [] + {}`. I'm not sure why you're getting a different result but it might be that your installation is doing the Chrome "trick" and actually evaluating `({} + [] === [] + {})` - might be a setting for it or a new feature from the latest version. – VLAZ Jun 25 '18 at 12:22
6

    var array = ['test1', 'test2', 'test3']
    var emptyObject = {}

    console.log(typeof(array+emptyObject));
    console.log(array+emptyObject);
    console.log(emptyObject+array);
    console.log(array+emptyObject === emptyObject+array);

    var array = [];
    var emptyObject = {}

    console.log(typeof(array+emptyObject));
    console.log(array+emptyObject);
    console.log(emptyObject+array);
    console.log(array+emptyObject === emptyObject+array);

    var array = ['firstArrayElement', 'secondArrayElement'];
    var object = {a:1, b:2}
    
    console.log(typeof(array+object));
    console.log(array+object);
    console.log(object+array);
    console.log(array+object === object+array);

    console.log(['a','b']+['c','d']);

When you convert an empty array to string you will receive empty string.

When you convert an object({}) to string you will always receive string: "[object Object]".

Plus operator is not defined for arrays and objects so JS always convert array and object to string when you use plus operator.

Krzysztof Raciniewski
  • 4,735
  • 3
  • 21
  • 42