JavaScript/JavaScript Fundamentals for Frontend Interviews/Equality, Coercion & Comparison Traps

Equality, Coercion & Comparison Traps

Medium100% Free~25 mins#equality#strict-equality#loose-equality#object-is#relational-operators#nan#coercion#edge-cases
Key Learning Objectives
✓

Master the 4 ECMAScript equality algorithms: isLooselyEqual (==), isStrictlyEqual (===), SameValueZero, and SameValue (Object.is).

✓

Understand why null >= 0 is true while null == 0 is false and null > 0 is false.

✓

Learn the mechanics of relational string comparisons (lexicographical character code order).

✓

Understand Object.is() edge cases: differentiating +0 and -0, and evaluating NaN equality.

✓

Avoid truthiness and coercion traps with empty arrays, zeros, and boolean coercion in interview code puzzles.

The Interview Problem

What is logged to the console when the following equality and relational comparisons execute, and why do loose equality and relational operators handle null and arrays with fundamentally different rules?

1const c1 = null >= 0;
2const c2 = null == 0;
3const c3 = '12' < '9';
4const c4 = Object.is(NaN, NaN);
5const c5 = Object.is(+0, -0);
6const c6 = [0] == false;
7
8console.log(c1, c2, c3, c4, c5, c6);
Predict Console Output
Interactive Challenge

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

true false true true false true

false false false false true false

true true true true false true

true false false true true false

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

Relational operator >= triggers ToNumber on null, yielding 0. Evaluates 0 >= 0, returning true.

Call Stack (Top = Active)
Global Execution Context
Lexical Scope / Bindings
c1:true (ToNumber(null) is 0; 0 >= 0 is true)
Console Stream
> [empty]

Deep Technical Breakdown

The Four Equality Algorithms in ECMAScript

JavaScript defines four distinct equality mechanisms in the standard specification:

  1. Abstract Equality (==): Coerces types if operands are different types (e.g. string to number, object to primitive via [Symbol.toPrimitive]('default') / valueOf() / toString()).
  2. Strict Equality (===): Returns false immediately if types differ. Exceptions: NaN === NaN is false, and +0 === -0 is true.
  3. SameValueZero: Used internally by Map, Set, and Array.prototype.includes(). Treats NaN as equal to NaN, and +0 as equal to -0.
  4. SameValue (Object.is()): Distinguishes +0 from -0 (evaluates to false), and treats NaN as equal to NaN (evaluates to true).

The Great null Comparison Paradox

Candidates are frequently stumped by this classic interview trio:

javascript
null > 0;  // false
null == 0; // false
null >= 0; // true!

Why does this happen?

  • For > and <: The engine runs ToNumber(null), which returns 0. It then tests 0 > 0, which is false.
  • For ==: The engine does NOT run ToNumber. Step 2 & 3 of the Abstract Equality Comparison rule state: If Type(x) is Null and Type(y) is Undefined, return true (and vice versa). Null is never coerced to a number in ==. Therefore, null == 0 is false.
  • For >=: In JavaScript, a >= b is formally defined as !(a < b). The engine tests null < 0: ToNumber(null) is 0, so 0 < 0 is false. Negating false yields true!

Lexicographical String Comparisons

If both operands to <, <=, >, >= are strings, no numeric coercion happens:

javascript
'12' < '9'; // true, because '1' (code 49) < '9' (code 57)
'apple' < 'banana'; // true

However, if one operand is a number, the string is coerced to a number:

javascript
'12' < 9; // false, because Number('12') is 12, and 12 < 9 is false

Polyfill: Object.is

javascript
function objectIs(x, y) {
  if (x === y) {
    // Differentiate +0 from -0: 1 / +0 is +Infinity, while 1 / -0 is -Infinity!
    return x !== 0 || 1 / x === 1 / y;
  }
  // Differentiate NaN: NaN is the only value in JavaScript not equal to itself
  return x !== x && y !== y;
}
Common Traps & Mistakes

Assuming `null == 0` is true because `null >= 0` is true. `==` never coerces null to number 0.

Assuming `'12' < '9'` evaluates numerically to false. String relational comparisons compare ASCII/Unicode character values.

Using `===` to check if a value is `NaN`. Always use `Number.isNaN(val)` or `Object.is(val, NaN)`.

Confusing `[0] == false` (true due to coercion) with `Boolean([0])` (truthy because all objects and arrays are truthy).

FAANG Follow-Up Probes
Probe #1

How does Array.prototype.indexOf differ from Array.prototype.includes when searching for NaN in an array?

Probe #2

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

Probe #3

How does the ToPrimitive algorithm prioritize [Symbol.toPrimitive], valueOf(), and toString() during coercion?