Coercion & Mutation Traps

Hard100% Free~30 mins#coercion#mutation#references#abstract-equality#output-prediction#object-keys
Key Learning Objectives
✓

Master object property key coercion: understand why plain objects stringify to '[object Object]' when used as keys.

✓

Understand reference passing vs parameter reassignment in JavaScript function calls.

✓

Analyze binary plus operand coercion with Array and Object instances via ToPrimitive and toString.

✓

Master abstract equality (==) special rules for null and undefined compared to strict equality (===).

✓

Confidently solve complex multi-paradigm interview output prediction puzzles.

The Interview Problem

What is logged to the console when the following object property indexing, array parameter mutation, and primitive coercion expressions execute?

1const a = {};
2const b = { key: 'b' };
3const c = { key: 'c' };
4
5a[b] = 123;
6a[c] = 456;
7
8const arr = [1, 2, 3];
9function mutate(list, item) {
10 list.push(item);
11 list = [99];
12 list.push(100);
13}
14mutate(arr, 4);
15
16const res1 = a[b];
17const res2 = arr.length;
18const res3 = [] + {};
19const res4 = (null == undefined) + '-' + (null === undefined);
20
21console.log(res1, res2, res3, res4);
Predict Console Output
Interactive Challenge

Select the option that matches what standard ECMAScript prints to the console:

456 4 [object Object] true-false

123 5 [object Object] true-true

456 5 [object Object] false-false

undefined 4 {} true-false

V8 Engine Execution Trace
Step 1 of 7 (Line 1)

Allocates plain objects a, b, and c in heap memory.

Call Stack (Top = Active)
Global Execution Context
Lexical Scope / Bindings
a:{}
b:{ key: 'b' }
c:{ key: 'c' }
Console Stream
> [empty]

Deep Technical Breakdown

1. Object Property Key Coercion

In standard JavaScript objects ({}), property keys can only be Strings or Symbols. When an object (b) is passed into bracket notation a[b], JavaScript invokes the internal abstract operation ToPropertyKey(b):

  1. b.toString() is called, which evaluates to "[object Object]" via Object.prototype.toString.
  2. Therefore, a[b] = 123 executes as a["[object Object]"] = 123.
  3. When a[c] = 456 runs, c also coerces to "[object Object]"!
  4. This directly overwrites the key, resulting in a[b] === 456.

(Note: To use object references as distinct keys without string coercion, use an ES6 Map instead).

2. Pass-by-Sharing & Parameter Reassignment

JavaScript is strictly pass-by-value. When passing an object reference to a function:

  • The parameter (list) receives a copy of the reference pointer pointing to the same array in heap memory.
  • Mutating the object via list.push(item) mutates the shared heap object (arr).
  • Reassigning the parameter (list = [99]) merely updates the local variable pointer list to point to a newly allocated array. It does not reassign the caller's variable arr.
  • Subsequent mutations on list only affect the new array.

3. Binary Plus & Type Coercion

In binary expressions A + B, if either operand is an object, JavaScript applies ToPrimitive(hint: "default"):

  • [].toString() produces "" (empty string).
  • ({}).toString() produces "[object Object]".
  • "" + "[object Object]" concatenates into "[object Object]".

4. Nullish Equality Rules

  • Abstract Equality (null == undefined): The ECMAScript specification (§ 7.2.14, Step 2-3) explicitly defines that null == undefined is true, and neither null nor undefined coerces to anything else in abstract equality.
  • Strict Equality (null === undefined): null has type object (historical bug) while undefined has type undefined. Because their primitive types differ, strict equality is unconditionally false.
Common Traps & Mistakes

Assuming plain JavaScript objects support object identity as keys. Object keys are always converted to strings unless they are Symbols.

Believing that reassigning a function parameter (`list = []`) reassigns the caller's variable.

Expecting `null == 0` to be true. While `Number(null)` is `0`, abstract equality comparison specifically dictates that `null` only loosely equals `undefined` and nothing else.

Confusing `{}` evaluated in statement position (interpreted as an empty block) with `{}` evaluated as an expression operand.

FAANG Follow-Up Probes
Probe #1

What does Map use instead of string coercion for object keys, and what equality algorithm powers it?

Probe #2

Why does [] == ![] evaluate to true in JavaScript?

Probe #3

How can you make a custom object return a custom primitive value during type coercion using Symbol.toPrimitive?