Engrain by ByteRush

JS.05.03 Mid-level· 10 minCore — asked often

Equality in JavaScript: ==, ===, Object.is and SameValueZero

JavaScript has four kinds of equality. Learn the == steps, why NaN !== NaN, how +0 and -0 differ, and which one includes, Map and Set use.

Comes up in: JavaScript, Recruiter screen

Learn#

Kiran’s analytics filter removes bad rows with rows.filter((r) => r.value !== NaN). Nothing is removed. NaN is not equal to anything — not even itself — so that check is always true.

JavaScript has four equality rules:

  • Loose equality == converts types first: null and undefined equal each other and nothing else; a boolean becomes a number; a string compared with a number becomes a number; an object becomes a primitive.
  • Strict equality === never converts. Different types are never equal.
  • SameValue, used by Object.is, is === with two fixes: NaN equals NaN, and +0 and -0 are different.
  • SameValueZero is like SameValue, but +0 equals -0. includes, Map and Set use it.
console.log(null == undefined, null == 0, "1" == 1, [] == false, [] == ![]);
console.log(NaN === NaN, Number.isNaN(NaN), +0 === -0, Object.is(+0, -0), Object.is(NaN, NaN));
console.log([NaN].includes(NaN), [NaN].indexOf(NaN), new Set([+0, -0]).size);

Output (verified)

true false true true true
false true true false true
true -1 1

indexOf uses ===, so it cannot find NaN; includes can. -0 appears when you round a small negative number, like Math.round(-0.4).

Why [] == ![] is trueStep 1 of 4

left

  • []

right

  • false

[] == ![] — first, ![] is evaluated. [] is truthy, so ![] is false.

Read the steps as text
  1. [] == ![] — first, ![] is evaluated. [] is truthy, so ![] is false.
  2. A boolean on one side is converted to a number: false → 0.
  3. Object vs number: the object goes through ToPrimitive. [] → ''.
  4. String vs number: the string becomes a number. '' → 0. Now 0 == 0 is true.

Predict#

Predict first

null == 0 — true or false? (Hint: null >= 0 is true.)

Interview angle#

Say it like this — about 30 seconds

“=== compares without converting. == converts first: null and undefined only equal each other, booleans become numbers, strings compared with numbers become numbers, and objects become primitives. Object.is is like === but treats NaN as equal to itself and +0 and -0 as different. SameValueZero, used by includes, Map and Set, also matches NaN but treats the zeros as equal. I use === by default, == null to catch null or undefined, and Number.isNaN for NaN.”

Stays on your device. Nothing is uploaded.
Follow-up Why is [] == false true?
The boolean becomes 0. The array becomes the primitive ” through ToPrimitive, then 0. And 0 == 0.
Follow-up How do you check for NaN?
Number.isNaN(x). The global isNaN converts first, so isNaN("abc") is true for a string.
Follow-up What is the difference between Object.is and ===?
Only two cases: Object.is(NaN, NaN) is true, and Object.is(+0, -0) is false.

Practice#

On your own

Implement the spec’s SameValue and SameValueZero using only === and arithmetic.

Done when

  • sameValue(NaN, NaN) is true and sameValue(0, -0) is false.
  • sameValueZero(NaN, NaN) and sameValueZero(0, -0) are both true.
  • Everything else matches ===, including objects compared by identity.
Your solution
Ctrl/⌘ + Enter

Remember#

Try to answer each card before you open it. Then add them to your reviews.

Which values does null == x match?

Only null and undefined.

How does Object.is differ from ===?

Object.is(NaN, NaN) is true; Object.is(+0, -0) is false.

Which equality do includes, Map and Set use?

SameValueZero: NaN matches NaN, +0 matches -0.

How do you reliably test for NaN?

Number.isNaN(x).

Go deeper

Four layers. Stop at the one your interview needs; each ends with a quick check.

The core ideaEvery round

Use ===. Use Number.isNaN for NaN. Remember includes/Map/Set find NaN, and indexOf does not.

Check yourself: Can [NaN].indexOf(NaN) find it?

No — indexOf uses ===. Use includes.

How it works underneathSenior rounds

== follows IsLooselyEqual, a short list of conversion steps Source: ECMA-262: IsLooselyEqual. Object.is uses SameValue, and collections use SameValueZero Source: MDN: Equality comparisons and sameness.

Check yourself: What is the spec name of the == algorithm?

IsLooselyEqual.

Edge cases and trapsWhere people slip

1 / -0 is -Infinity, which is how old code told the zeros apart. JSON.stringify(-0) is “0”. Objects are equal only to themselves under every rule — two arrays with the same items are never ==.

Check yourself: How can you tell -0 from +0 without Object.is?

1 / x is -Infinity for -0 and Infinity for +0.

In productionStaff-level answers

Turn on ESLint eqeqeq with { null: "ignore" } to allow == null. React’s useEffect dependencies and useMemo compare with Object.is — so a new array or object every render always counts as a change (RCT.03).

Check yourself: Which ESLint rule enforces ===, while allowing == null?

eqeqeq with the "smart" or { null: "ignore" } option.

Finished the five steps? Mark it, and its cards join your reviews.

Last checked 2026-10-31. Spot a mistake? Use “Report an error” below — fixes are listed on the corrections page.

Interview questions this answers

  • Explain how == works. Why is [] == false true?
  • What is the difference between Object.is and ===?
  • What is NaN? How do you check for it?