In JavaScript, ([] + {}) evaluates to the string '[object Object]', but a script line that starts with {} + [] evaluates to 0. Explain both results.
answer
- two different mechanisms, not one
- empty array stringifies to nothing
- braces mean different things by position
- the second plus is unary
- parentheses change the parse, not the values
basics
~20 sTwo different mechanisms. In expression position both operands convert to primitives — '' and '[object Object]' — and + concatenates. At the start of a statement, {} parses as an empty block, so what remains is unary +[], which converts the empty array to '' and then to the number 0.
solid answer
~40 s`[] + {}` is pure coercion: binary `+` converts each operand with the default hint, so the array becomes `''` (its `join`) and the object becomes `'[object Object]'` (from `Object.prototype.toString`); one operand is a string, so `+` concatenates and you get `'[object Object]'`. The second case is a **parsing** result, not a coercion one. At the start of a statement a `{` begins a block, so `{}` is an empty block statement and the rest of the line is the separate expression statement `+[]` — unary plus, which does `ToNumber([])`, giving `''` and then `0`. Wrap it in parentheses or assign it and `{}` is unambiguously an object literal again, so `({} + [])` is `'[object Object]'`. The lesson is that the same characters mean different things in statement and expression position.
code
javascript · 9 lines// expression position: binary + and coercion
console.log([] + {}); // '[object Object]'
console.log(({} + [])); // '[object Object]'
console.log(typeof ({} + [])); // 'string'
// statement position: empty block, then unary +
// (run as a script, not typed into a console)
{} + []; // completion value 0
console.log(+[]); // 0 — the unary part on its owngo deeper
Recall that an empty array stringifies to the empty string and a plain object to '[object Object]', and that seeing '[object Object]' in output means an object reached a string context.
Separate the two mechanisms cleanly: coercion in expression position versus a leading brace parsed as a block plus a unary operator. Show that parentheses restore the object-literal reading.
Connect it to bugs you have shipped — an arrow function returning undefined because its object literal was parsed as a block, or '[object Object]' turning up in a cache key — and say how linting and explicit conversion prevent both.
Treat puzzles like this as a signal about house style: ban implicit object-to-string conversion at boundaries, standardise on explicit serialisation, and judge whether such trivia belongs in your interview loop at all versus questions with production consequences.
## Result one: ordinary coercion `[] + {}` in expression position exercises nothing exotic. Binary `+` runs `ToPrimitive` on each operand with the **default** hint, which for ordinary objects means "try `valueOf()`, then `toString()`". - `[]`: `Array.prototype.valueOf` is inherited from `Object.prototype` and returns the array itself — not a primitive — so `Array.prototype.toString` runs, which is `join(',')` over zero elements: the empty string `''`. - `{}`: same fall-through, and `Object.prototype.toString` returns `'[object Object]'`. Now `+` applies its rule: at least one primitive is a string, so both are stringified and concatenated. `'' + '[object Object]'` is `'[object Object]'`. ```js String([]); // '' String({}); // '[object Object]' [] + {}; // '[object Object]' [] + []; // '' [1,2] + [3]; // '1,23' ``` ## Result two: it is a parsing question JavaScript's grammar is ambiguous about `{`. At the point where the parser expects a **statement**, `{` starts a *block*; where it expects an **expression**, `{` starts an *object literal*. A line beginning `{} + []` is at statement position, so the parser sees: 1. `{}` — an empty block statement, which produces no value; 2. `+[]` — a separate expression statement using **unary** plus. Unary `+` is a different operator from binary `+`: it performs `ToNumber` and can never concatenate. `ToNumber([])` goes through `ToPrimitive` with the number hint, gets `''`, and `Number('')` is `0`. So the completion value of the line is `0`. The moment you put the same characters somewhere an expression is expected, `{}` is an object literal again and the binary operator returns: ```js ({} + []); // '[object Object]' — parenthesised, expression position const x = {} + []; // '[object Object]' — after '=', expression position console.log({} + []); // '[object Object]' — argument position ``` Be careful drawing conclusions from a REPL or a browser console: these tools decide for themselves whether to evaluate your input as a statement or wrap it as an expression, and they have differed on exactly this input. If you want to know what the language does, put the code in a script and use an explicit position. ## The same ambiguity elsewhere This is not a one-off curiosity; the statement-versus-expression rule for `{` shows up in normal code: ```js // Arrow function returning an object needs parentheses, // otherwise the body is read as a block: const make = () => ({ ok: true }); // returns an object const broken = () => { ok: true }; // returns undefined ``` In `broken`, `{ ok: true }` is a block containing a labelled statement `ok:` whose body is the expression `true` — valid syntax, no value returned. The same grammar rule explains why an IIFE is written `(function(){})()` or `!function(){}()`: a bare `function` at statement position is a declaration, not an expression. ## What a candidate should take away The interesting half of this puzzle is not `'[object Object]'` — it is that a JavaScript answer can hinge on parsing rather than on values. When output surprises you, ask two questions in order: *how did the parser read this text*, and only then *what did the operators do with the values*. A frequent real-world instance is an arrow function whose object literal silently became a block, returning `undefined` with no error anywhere. And the coercion half has a practical edge too: `'[object Object]'` appearing in a log line, a URL or a cache key always means an object reached a string context without an intended conversion. That string is a defect signature — track it back to the `+`, template literal or `String()` call that produced it, and convert deliberately with `JSON.stringify`, a real `toString`, or an explicit field.
- Why is +[] equal to 0 but +{} equal to NaN?Unary `+` performs `ToNumber`, which first takes a primitive. `[]` stringifies to `''` via `join`, and `Number('')` is `0`. `{}` stringifies to `'[object Object]'`, which is not a valid numeric literal, so `ToNumber` yields `NaN`. Both take the identical path; only the intermediate string differs.
- Where else does the statement-versus-expression rule for braces bite in real code?Most often in a concise arrow function meant to return an object literal: `() => { ok: true }` parses the braces as a block and returns `undefined`, so you must write `() => ({ ok: true })`. The same rule is why a function expression used immediately needs wrapping, as in `(function () { ... })()` — a bare `function` at statement position is a declaration.
saying these in an interview costs you the question
- Explains both results with coercion alone, ignoring parsing
- Says the difference is operand order in binary +
- Claims JavaScript evaluates + right to left here
- Thinks {} always means an object literal
- Believes a browser console proves the language's parse