This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What is the explanation for these bizarre JavaScript behaviours mentioned in the 'Wat' talk for CodeMash 2012?
I know that when [] is coerced to a string it returns the empty string (""), and when {} is coerced to a string it returns "[object Object]".
When I run [] + {} in my browser's Javascript console, it returns as I would expect:
>> [] + {}
"[object Object]"
But when I run {} + [], it returns a completely unexpected value:
>> {} + []
0
What could be causing it to return 0?
When there is a { at the beginning of a statement, it will be interpreted as a block, which may contain zero or more statements. An block with no statements in it will have an empty continuation value.
In other words, in this case, {} is interpreted as an empty code block.
The statement ends after the ending brace }, which means that the next three characters +[] comprise a statement of their own.
At the beginning of an expression or statement, + is the unary plus operator, which coerces its operand to a number.
So +[] is the same as Number([]), which evaluates to 0.
In short, {} + [] is an empty code block followed by an array coerced to a number.
All that said, if you evaluate {} + [] inside an expression, it will return what you expect:
>> ({} + [])
"[object Object]"
Another interesting thing is that you cannot begin a statement with an object literal because the interpreter will try to parse it as a statement. Doing this
{ "object": "literal" };
will throw a syntax error.
Because the {} is treated as a block. Thus your statement is actually:
{
//empty block here
}
+[] //0 same as Number([])
This is why this is invalid javascript:
eval('{hello: "world", key: "value"}') //Syntax error
You can add () to make it an expression (blocks cannot be used in an expression so it will be object initializer:
eval('({hello: "world", key: "value"})') //Object
The empty block gets coerced into a zero. Then the + operator decides to coerce the [] to a number.
Related
The 'Wat' talk for CodeMash 2012 basically points out a few bizarre quirks with Ruby and JavaScript.
I have made a JSFiddle of the results at http://jsfiddle.net/fe479/9/.
The behaviours specific to JavaScript (as I don't know Ruby) are listed below.
I found in the JSFiddle that some of my results didn't correspond with those in the video, and I am not sure why. I am, however, curious to know how JavaScript is handling working behind the scenes in each case.
Empty Array + Empty Array
[] + []
result:
<Empty String>
I am quite curious about the + operator when used with arrays in JavaScript.
This matches the video's result.
Empty Array + Object
[] + {}
result:
[Object]
This matches the video's result. What's going on here? Why is this an object. What does the + operator do?
Object + Empty Array
{} + []
result:
[Object]
This doesn't match the video. The video suggests that the result is 0, whereas I get [Object].
Object + Object
{} + {}
result:
[Object][Object]
This doesn't match the video either, and how does outputting a variable result in two objects? Maybe my JSFiddle is wrong.
Array(16).join("wat" - 1)
result:
NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
Doing wat + 1 results in wat1wat1wat1wat1...
I suspect this is just straightforward behaviour that trying to subtract a number from a string results in NaN.
Here's a list of explanations for the results you're seeing (and supposed to be seeing). The references I'm using are from the ECMA-262 standard.
[] + []
When using the addition operator, both the left and right operands are converted to primitives first (§11.6.1). As per §9.1, converting an object (in this case an array) to a primitive returns its default value, which for objects with a valid toString() method is the result of calling object.toString() (§8.12.8). For arrays this is the same as calling array.join() (§15.4.4.2). Joining an empty array results in an empty string, so step #7 of the addition operator returns the concatenation of two empty strings, which is the empty string.
[] + {}
Similar to [] + [], both operands are converted to primitives first. For "Object objects" (§15.2), this is again the result of calling object.toString(), which for non-null, non-undefined objects is "[object Object]" (§15.2.4.2).
{} + []
The {} here is not parsed as an object, but instead as an empty block (§12.1, at least as long as you're not forcing that statement to be an expression, but more about that later). The return value of empty blocks is empty, so the result of that statement is the same as +[]. The unary + operator (§11.4.6) returns ToNumber(ToPrimitive(operand)). As we already know, ToPrimitive([]) is the empty string, and according to §9.3.1, ToNumber("") is 0.
{} + {}
Similar to the previous case, the first {} is parsed as a block with empty return value. Again, +{} is the same as ToNumber(ToPrimitive({})), and ToPrimitive({}) is "[object Object]" (see [] + {}). So to get the result of +{}, we have to apply ToNumber on the string "[object Object]". When following the steps from §9.3.1, we get NaN as a result:
If the grammar cannot interpret the String as an expansion of StringNumericLiteral, then the result of ToNumber is NaN.
Array(16).join("wat" - 1)
As per §15.4.1.1 and §15.4.2.2, Array(16) creates a new array with length 16. To get the value of the argument to join, §11.6.2 steps #5 and #6 show that we have to convert both operands to a number using ToNumber. ToNumber(1) is simply 1 (§9.3), whereas ToNumber("wat") again is NaN as per §9.3.1. Following step 7 of §11.6.2, §11.6.3 dictates that
If either operand is NaN, the result is NaN.
So the argument to Array(16).join is NaN. Following §15.4.4.5 (Array.prototype.join), we have to call ToString on the argument, which is "NaN" (§9.8.1):
If m is NaN, return the String "NaN".
Following step 10 of §15.4.4.5, we get 15 repetitions of the concatenation of "NaN" and the empty string, which equals the result you're seeing.
When using "wat" + 1 instead of "wat" - 1 as argument, the addition operator converts 1 to a string instead of converting "wat" to a number, so it effectively calls Array(16).join("wat1").
As to why you're seeing different results for the {} + [] case: When using it as a function argument, you're forcing the statement to be an ExpressionStatement, which makes it impossible to parse {} as empty block, so it's instead parsed as an empty object literal.
This is more of a comment than an answer, but for some reason I can't comment on your question. I wanted to correct your JSFiddle code. However, I posted this on Hacker News and someone suggested that I repost it here.
The problem in the JSFiddle code is that ({}) (opening braces inside of parentheses) is not the same as {} (opening braces as the start of a line of code). So when you type out({} + []) you are forcing the {} to be something which it is not when you type {} + []. This is part of the overall 'wat'-ness of Javascript.
The basic idea was simple JavaScript wanted to allow both of these forms:
if (u)
v;
if (x) {
y;
z;
}
To do so, two interpretations were made of the opening brace: 1. it is not required and 2. it can appear anywhere.
This was a wrong move. Real code doesn't have an opening brace appearing in the middle of nowhere, and real code also tends to be more fragile when it uses the first form rather than the second. (About once every other month at my last job, I'd get called to a coworker's desk when their modifications to my code weren't working, and the problem was that they'd added a line to the "if" without adding curly braces. I eventually just adopted the habit that the curly braces are always required, even when you're only writing one line.)
Fortunately in many cases eval() will replicate the full wat-ness of JavaScript. The JSFiddle code should read:
function out(code) {
function format(x) {
return typeof x === "string" ?
JSON.stringify(x) : x;
}
document.writeln('>>> ' + code);
document.writeln(format(eval(code)));
}
document.writeln("<pre>");
out('[] + []');
out('[] + {}');
out('{} + []');
out('{} + {}');
out('Array(16).join("wat" + 1)');
out('Array(16).join("wat - 1")');
out('Array(16).join("wat" - 1) + " Batman!"');
document.writeln("</pre>");
[Also that is the first time I have written document.writeln in many many many years, and I feel a little dirty writing anything involving both document.writeln() and eval().]
I second #Ventero’s solution. If you want to, you can go into more detail as to how + converts its operands.
First step (§9.1): convert both operands to primitives (primitive values are undefined, null, booleans, numbers, strings; all other values are objects, including arrays and functions). If an operand is already primitive, you are done. If not, it is an object obj and the following steps are performed:
Call obj.valueOf(). If it returns a primitive, you are done. Direct instances of Object and arrays return themselves, so you are not done yet.
Call obj.toString(). If it returns a primitive, you are done. {} and [] both return a string, so you are done.
Otherwise, throw a TypeError.
For dates, step 1 and 2 are swapped. You can observe the conversion behavior as follows:
var obj = {
valueOf: function () {
console.log("valueOf");
return {}; // not a primitive
},
toString: function () {
console.log("toString");
return {}; // not a primitive
}
}
Interaction (Number() first converts to primitive then to number):
> Number(obj)
valueOf
toString
TypeError: Cannot convert object to primitive value
Second step (§11.6.1): If one of the operands is a string, the other operand is also converted to string and the result is produced by concatenating two strings. Otherwise, both operands are converted to numbers and the result is produced by adding them.
More detailed explanation of the conversion process: “What is {} + {} in JavaScript?”
We may refer to the specification and that's great and most accurate, but most of the cases can also be explained in a more comprehensible way with the following statements:
+ and - operators work only with primitive values. More specifically +(addition) works with either strings or numbers, and +(unary) and -(subtraction and unary) works only with numbers.
All native functions or operators that expect primitive value as argument, will first convert that argument to desired primitive type. It is done with valueOf or toString, which are available on any object. That's the reason why such functions or operators don't throw errors when invoked on objects.
So we may say that:
[] + [] is same as String([]) + String([]) which is same as '' + ''. I mentioned above that +(addition) is also valid for numbers, but there is no valid number representation of an array in JavaScript, so addition of strings is used instead.
[] + {} is same as String([]) + String({}) which is same as '' + '[object Object]'
{} + []. This one deserves more explanation (see Ventero answer). In that case, curly braces are treated not as an object but as an empty block, so it turns out to be same as +[]. Unary + works only with numbers, so the implementation tries to get a number out of []. First it tries valueOf which in the case of arrays returns the same object, so then it tries the last resort: conversion of a toString result to a number. We may write it as +Number(String([])) which is same as +Number('') which is same as +0.
Array(16).join("wat" - 1) subtraction - works only with numbers, so it's the same as: Array(16).join(Number("wat") - 1), as "wat" can't be converted to a valid number. We receive NaN, and any arithmetic operation on NaN results with NaN, so we have: Array(16).join(NaN).
To buttress what has been shared earlier.
The underlying cause of this behaviour is partly due to the weakly-typed nature of JavaScript. For example, the expression 1 + “2” is ambiguous since there are two possible interpretations based on the operand types (int, string) and (int int):
User intends to concatenate two strings, result: “12”
User intends to add two numbers, result: 3
Thus with varying input types,the output possibilities increase.
The addition algorithm
Coerce operands to primitive values
The JavaScript primitives are string, number, null, undefined and boolean (Symbol is coming soon in ES6). Any other value is an object (e.g. arrays, functions and objects). The coercion process for converting objects into primitive values is described thus:
If a primitive value is returned when object.valueOf() is invoked, then return this value, otherwise continue
If a primitive value is returned when object.toString() is invoked, then return this value, otherwise continue
Throw a TypeError
Note: For date values, the order is to invoke toString before valueOf.
If any operand value is a string, then do a string concatenation
Otherwise, convert both operands to their numeric value and then add these values
Knowing the various coercion values of types in JavaScript does help to make the confusing outputs clearer. See the coercion table below
+-----------------+-------------------+---------------+
| Primitive Value | String value | Numeric value |
+-----------------+-------------------+---------------+
| null | “null” | 0 |
| undefined | “undefined” | NaN |
| true | “true” | 1 |
| false | “false” | 0 |
| 123 | “123” | 123 |
| [] | “” | 0 |
| {} | “[object Object]” | NaN |
+-----------------+-------------------+---------------+
It is also good to know that JavaScript's + operator is left-associative as this determines what the output will be cases involving more than one + operation.
Leveraging the
Thus 1 + "2" will give "12" because any addition involving a string will always default to string concatenation.
You can read more examples in this blog post (disclaimer I wrote it).
The 'Wat' talk for CodeMash 2012 basically points out a few bizarre quirks with Ruby and JavaScript.
I have made a JSFiddle of the results at http://jsfiddle.net/fe479/9/.
The behaviours specific to JavaScript (as I don't know Ruby) are listed below.
I found in the JSFiddle that some of my results didn't correspond with those in the video, and I am not sure why. I am, however, curious to know how JavaScript is handling working behind the scenes in each case.
Empty Array + Empty Array
[] + []
result:
<Empty String>
I am quite curious about the + operator when used with arrays in JavaScript.
This matches the video's result.
Empty Array + Object
[] + {}
result:
[Object]
This matches the video's result. What's going on here? Why is this an object. What does the + operator do?
Object + Empty Array
{} + []
result:
[Object]
This doesn't match the video. The video suggests that the result is 0, whereas I get [Object].
Object + Object
{} + {}
result:
[Object][Object]
This doesn't match the video either, and how does outputting a variable result in two objects? Maybe my JSFiddle is wrong.
Array(16).join("wat" - 1)
result:
NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
Doing wat + 1 results in wat1wat1wat1wat1...
I suspect this is just straightforward behaviour that trying to subtract a number from a string results in NaN.
Here's a list of explanations for the results you're seeing (and supposed to be seeing). The references I'm using are from the ECMA-262 standard.
[] + []
When using the addition operator, both the left and right operands are converted to primitives first (§11.6.1). As per §9.1, converting an object (in this case an array) to a primitive returns its default value, which for objects with a valid toString() method is the result of calling object.toString() (§8.12.8). For arrays this is the same as calling array.join() (§15.4.4.2). Joining an empty array results in an empty string, so step #7 of the addition operator returns the concatenation of two empty strings, which is the empty string.
[] + {}
Similar to [] + [], both operands are converted to primitives first. For "Object objects" (§15.2), this is again the result of calling object.toString(), which for non-null, non-undefined objects is "[object Object]" (§15.2.4.2).
{} + []
The {} here is not parsed as an object, but instead as an empty block (§12.1, at least as long as you're not forcing that statement to be an expression, but more about that later). The return value of empty blocks is empty, so the result of that statement is the same as +[]. The unary + operator (§11.4.6) returns ToNumber(ToPrimitive(operand)). As we already know, ToPrimitive([]) is the empty string, and according to §9.3.1, ToNumber("") is 0.
{} + {}
Similar to the previous case, the first {} is parsed as a block with empty return value. Again, +{} is the same as ToNumber(ToPrimitive({})), and ToPrimitive({}) is "[object Object]" (see [] + {}). So to get the result of +{}, we have to apply ToNumber on the string "[object Object]". When following the steps from §9.3.1, we get NaN as a result:
If the grammar cannot interpret the String as an expansion of StringNumericLiteral, then the result of ToNumber is NaN.
Array(16).join("wat" - 1)
As per §15.4.1.1 and §15.4.2.2, Array(16) creates a new array with length 16. To get the value of the argument to join, §11.6.2 steps #5 and #6 show that we have to convert both operands to a number using ToNumber. ToNumber(1) is simply 1 (§9.3), whereas ToNumber("wat") again is NaN as per §9.3.1. Following step 7 of §11.6.2, §11.6.3 dictates that
If either operand is NaN, the result is NaN.
So the argument to Array(16).join is NaN. Following §15.4.4.5 (Array.prototype.join), we have to call ToString on the argument, which is "NaN" (§9.8.1):
If m is NaN, return the String "NaN".
Following step 10 of §15.4.4.5, we get 15 repetitions of the concatenation of "NaN" and the empty string, which equals the result you're seeing.
When using "wat" + 1 instead of "wat" - 1 as argument, the addition operator converts 1 to a string instead of converting "wat" to a number, so it effectively calls Array(16).join("wat1").
As to why you're seeing different results for the {} + [] case: When using it as a function argument, you're forcing the statement to be an ExpressionStatement, which makes it impossible to parse {} as empty block, so it's instead parsed as an empty object literal.
This is more of a comment than an answer, but for some reason I can't comment on your question. I wanted to correct your JSFiddle code. However, I posted this on Hacker News and someone suggested that I repost it here.
The problem in the JSFiddle code is that ({}) (opening braces inside of parentheses) is not the same as {} (opening braces as the start of a line of code). So when you type out({} + []) you are forcing the {} to be something which it is not when you type {} + []. This is part of the overall 'wat'-ness of Javascript.
The basic idea was simple JavaScript wanted to allow both of these forms:
if (u)
v;
if (x) {
y;
z;
}
To do so, two interpretations were made of the opening brace: 1. it is not required and 2. it can appear anywhere.
This was a wrong move. Real code doesn't have an opening brace appearing in the middle of nowhere, and real code also tends to be more fragile when it uses the first form rather than the second. (About once every other month at my last job, I'd get called to a coworker's desk when their modifications to my code weren't working, and the problem was that they'd added a line to the "if" without adding curly braces. I eventually just adopted the habit that the curly braces are always required, even when you're only writing one line.)
Fortunately in many cases eval() will replicate the full wat-ness of JavaScript. The JSFiddle code should read:
function out(code) {
function format(x) {
return typeof x === "string" ?
JSON.stringify(x) : x;
}
document.writeln('>>> ' + code);
document.writeln(format(eval(code)));
}
document.writeln("<pre>");
out('[] + []');
out('[] + {}');
out('{} + []');
out('{} + {}');
out('Array(16).join("wat" + 1)');
out('Array(16).join("wat - 1")');
out('Array(16).join("wat" - 1) + " Batman!"');
document.writeln("</pre>");
[Also that is the first time I have written document.writeln in many many many years, and I feel a little dirty writing anything involving both document.writeln() and eval().]
I second #Ventero’s solution. If you want to, you can go into more detail as to how + converts its operands.
First step (§9.1): convert both operands to primitives (primitive values are undefined, null, booleans, numbers, strings; all other values are objects, including arrays and functions). If an operand is already primitive, you are done. If not, it is an object obj and the following steps are performed:
Call obj.valueOf(). If it returns a primitive, you are done. Direct instances of Object and arrays return themselves, so you are not done yet.
Call obj.toString(). If it returns a primitive, you are done. {} and [] both return a string, so you are done.
Otherwise, throw a TypeError.
For dates, step 1 and 2 are swapped. You can observe the conversion behavior as follows:
var obj = {
valueOf: function () {
console.log("valueOf");
return {}; // not a primitive
},
toString: function () {
console.log("toString");
return {}; // not a primitive
}
}
Interaction (Number() first converts to primitive then to number):
> Number(obj)
valueOf
toString
TypeError: Cannot convert object to primitive value
Second step (§11.6.1): If one of the operands is a string, the other operand is also converted to string and the result is produced by concatenating two strings. Otherwise, both operands are converted to numbers and the result is produced by adding them.
More detailed explanation of the conversion process: “What is {} + {} in JavaScript?”
We may refer to the specification and that's great and most accurate, but most of the cases can also be explained in a more comprehensible way with the following statements:
+ and - operators work only with primitive values. More specifically +(addition) works with either strings or numbers, and +(unary) and -(subtraction and unary) works only with numbers.
All native functions or operators that expect primitive value as argument, will first convert that argument to desired primitive type. It is done with valueOf or toString, which are available on any object. That's the reason why such functions or operators don't throw errors when invoked on objects.
So we may say that:
[] + [] is same as String([]) + String([]) which is same as '' + ''. I mentioned above that +(addition) is also valid for numbers, but there is no valid number representation of an array in JavaScript, so addition of strings is used instead.
[] + {} is same as String([]) + String({}) which is same as '' + '[object Object]'
{} + []. This one deserves more explanation (see Ventero answer). In that case, curly braces are treated not as an object but as an empty block, so it turns out to be same as +[]. Unary + works only with numbers, so the implementation tries to get a number out of []. First it tries valueOf which in the case of arrays returns the same object, so then it tries the last resort: conversion of a toString result to a number. We may write it as +Number(String([])) which is same as +Number('') which is same as +0.
Array(16).join("wat" - 1) subtraction - works only with numbers, so it's the same as: Array(16).join(Number("wat") - 1), as "wat" can't be converted to a valid number. We receive NaN, and any arithmetic operation on NaN results with NaN, so we have: Array(16).join(NaN).
To buttress what has been shared earlier.
The underlying cause of this behaviour is partly due to the weakly-typed nature of JavaScript. For example, the expression 1 + “2” is ambiguous since there are two possible interpretations based on the operand types (int, string) and (int int):
User intends to concatenate two strings, result: “12”
User intends to add two numbers, result: 3
Thus with varying input types,the output possibilities increase.
The addition algorithm
Coerce operands to primitive values
The JavaScript primitives are string, number, null, undefined and boolean (Symbol is coming soon in ES6). Any other value is an object (e.g. arrays, functions and objects). The coercion process for converting objects into primitive values is described thus:
If a primitive value is returned when object.valueOf() is invoked, then return this value, otherwise continue
If a primitive value is returned when object.toString() is invoked, then return this value, otherwise continue
Throw a TypeError
Note: For date values, the order is to invoke toString before valueOf.
If any operand value is a string, then do a string concatenation
Otherwise, convert both operands to their numeric value and then add these values
Knowing the various coercion values of types in JavaScript does help to make the confusing outputs clearer. See the coercion table below
+-----------------+-------------------+---------------+
| Primitive Value | String value | Numeric value |
+-----------------+-------------------+---------------+
| null | “null” | 0 |
| undefined | “undefined” | NaN |
| true | “true” | 1 |
| false | “false” | 0 |
| 123 | “123” | 123 |
| [] | “” | 0 |
| {} | “[object Object]” | NaN |
+-----------------+-------------------+---------------+
It is also good to know that JavaScript's + operator is left-associative as this determines what the output will be cases involving more than one + operation.
Leveraging the
Thus 1 + "2" will give "12" because any addition involving a string will always default to string concatenation.
You can read more examples in this blog post (disclaimer I wrote it).
Could you please explain why the results are different?
({} + {}) // = "[object Object][object Object]"
{} + {} // = NaN
I understand that in both cases objects are converted to strings, but why in the second case the result is converted to a number?
From:
http://www.2ality.com/2012/01/object-plus-object.html
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()
...
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:
({} + {})
'[object Object][object Object]'
This question already has answers here:
What is the explanation for these bizarre JavaScript behaviours mentioned in the 'Wat' talk for CodeMash 2012?
(5 answers)
Closed 7 years ago.
Why do the following computations in Javascript give these results?
{} + []
0
[] + {}
"[object Object]"
{} + {}
NaN
[] + []
""
What is going on?
Although it looks like all of your examples are using the addition operator, in fact half of them are using the addition operator (the binary +), and half are using the unary + operator.
These are using the addition operator:
[] + {}
[] + []
and these are using the unary + operator:
{} + []
{} + {}
Let's start with the first two:
[] + {}
[] + []
The JavaScript addition operator is defined in terms of strings (concatenation) and numbers (addition), and so when its operands are not strings or numbers, it coerces them to be.
Full details in the specification, but basically: First both arguments are converted to primitives via the abstract ToPrimitive operation, which may result in any of several primitive types (string, number, boolean). Then if either operand is a string, the other operand is coerced to be a string and concatenation is done. If not, both are coerced to numbers and addition is carried out.
So if you play with Number({}) and String({}) and Number([]) and String([]), you'll see what's going on.
Now, let's look at the other two:
{} + []
{} + {}
These are really tricky because they look like addition, but they aren't: They're an empty block followed by an expression using the unary + operator. When expecting either a statement or expression, if the parser sees {}, it processes it as a block statement. Since those blocks are empty, they don't do anything at all and we're left with:
+ []
+ {}
That ends up coercing the array or object to a number. Number([]) is 0, and Number({}) is NaN.
If we force the parser to expect just an expression (perhaps by using ()), not either an expression or statement, we see a different result because we're back to the addition operator:
({} + [])
"[object Object]"
{} + {}
"[object Object][object Object]"
I'm a beginner developer, and I can't understand why below statements have such outputs. Can someone explain that how/why following two expressions are interpenetrated by JavaScript differently, that their outputs are different.
1 + {} // => "1[object Object]"
{} + 1 // => 1
As + is a commutative operator so I was expecting same answer but it seems I am missing some language rules.
In JavaScript, the addition operator (+) adds the value of one numeric expression to another, or concatenates two strings.
The types of the two expressions determine the behavior of the + operator.
If both expressions are numeric or Boolean, then they are added.
1 + 1;
// 2
true + false;
// 1
true + true;
// 2
If both expressions are strings, they are concatenated:
"hel" + "lo";
// "hello"
If one expression is numeric and the other is a string they are also concatenated:
1 + {}
// "1[object Object]"
Here [object Object] is the string representation of {}:
String({})
// "[object Object]"
So hopefully the first example is clear.
However, things get weird if the first operand of + is an empty object literal. JavaScript interprets this as an empty code block and ignores it.
Hence, {} + 1 is simply interpreted as +1, which is obviously 1.
So, 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.
You can fix this by forcing the input to be parsed as an expression, which then gives you the output you would expect:
({} + 1)
// "[object Object]1"
You might alike to read this great post to find out more.