Skip to content
SDETRole
SDETRole

JavaScript interview question

What is the difference between == and ===, and how do you compare objects in tests?

beginner 0–2 yrs #equality#type-coercion#deep-equality#assertions

Short answer

=== compares without type conversion; == applies type coercion first, giving surprises like 0 == '' being true. Both compare objects by reference, not content, so two identical objects are not equal. In tests use deep equality such as toEqual or toStrictEqual, and use Object.is semantics for NaN and -0.

Answer

=== (strict equality) returns true only if both operands have the same type and the same value; it never converts types. == (loose equality) first coerces the operands to a common type using a set of rules that produce surprising results. Use === everywhere, with the one common, deliberate exception x == null, which checks for both null and undefined.

Coercion surprises with ==

0 == '';            // true  ('' converts to 0)
0 == '0';           // true
'' == '0';          // false (both strings, compared directly)
false == '0';       // true  (both become 0)
null == undefined;  // true
null == 0;          // false (null only loosely equals undefined)
[1] == 1;           // true  ([1] -> '1' -> 1)

Note that == is not even transitive (0 == '' and 0 == '0', but '' != '0'). That is reason enough to avoid it.

Objects are compared by reference

Both operators compare objects, arrays and functions by identity, not content:

const a = { id: 1 };
const b = { id: 1 };
a === b;  // false: two different objects
a === a;  // true
[1, 2] === [1, 2]; // false

This is the source of a common test bug:

// Wrong: compares references, always fails for a freshly parsed body
expect(await response.json()).toBe({ id: 1 });

// Right: deep equality
expect(await response.json()).toEqual({ id: 1 });

Deep equality in test frameworks

  • Jest / Vitest / Playwright expect: toBe uses Object.is (identity for objects). toEqual recursively compares content and ignores properties whose value is undefined. toStrictEqual also checks undefined properties, sparse arrays and class types.
  • Partial matching: toMatchObject({ status: 'paid' }) or expect.objectContaining(...) to assert only the fields you care about, which keeps API tests resilient to new fields.
  • Node: assert.deepStrictEqual(a, b) or util.isDeepStrictEqual(a, b).

NaN and -0

NaN is the only value not equal to itself, even with ===:

NaN === NaN;          // false
Number.isNaN(NaN);    // true
Object.is(NaN, NaN);  // true
Object.is(0, -0);     // false, whereas 0 === -0 is true

Object.is is what toBe uses, which is why expect(NaN).toBe(NaN) passes.

What interviewers look for

  • Strict versus loose with at least one concrete coercion example.
  • Reference equality for objects, and the toBe versus toEqual consequence in tests.
  • Awareness of partial matchers for API assertions.
  • Bonus: NaN, Object.is, and the == null idiom.

A strong answer covers

  • === is strict equality with no type conversion
  • == performs type coercion, with examples of surprises
  • Objects and arrays are compared by reference
  • Uses deep equality in tests (toEqual, toStrictEqual, deepStrictEqual)
  • Mentions NaN and Object.is edge cases
Practise answering under time pressure

Type to search across SDETRole.

Full-text search by Pagefind · runs in your browser Open search page →