Interview answer drill

Use this JavaScript interview question to rehearse a quick answer, common mistake, follow-up, and production pitfall.

How would you compare two objects in JavaScript?Frontend interview answer

HighIntermediateJavascript
Interview focus

This JavaScript interview question tests whether you can explain compare two objects in JavaScript: shallow vs deep vs JSON pitfalls, connect it to production trade-offs, and handle common follow-up questions.

  • compare two objects in JavaScript: shallow vs deep vs JSON pitfalls explanation without falling back to memorized docs wording
  • Objects and Equality reasoning, edge cases, and production failure modes
  • How you would answer the most likely JavaScript interview follow-up
Practice more JavaScript interview questions
Interview quick answer

Object comparison in JavaScript is a strategy decision: === checks identity, shallow checks fit flat data, and deep checks fit nested data. Learn when each approach is enough, where JSON.stringify breaks, and which edge cases need a real deep-equality helper.

Full interview answer

The core idea

Object comparison in JavaScript is not one single operation. You choose the cheapest comparison strategy that matches your intent:

  • Identity comparison: are both variables pointing to the exact same object?
  • Shallow value comparison: are top-level keys and values equal?
  • Deep value comparison: are nested objects/arrays equal by content?

Most interview mistakes happen when people use === but expect deep value equality, or when they deep-compare everything even though a flat shallow check would have been enough.

JAVASCRIPT
const a = { id: 1, profile: { city: 'Berlin' } };
const b = { id: 1, profile: { city: 'Berlin' } };
const c = a;

console.log(a === b); // false (different references)
console.log(a === c); // true  (same reference)
                  

Approach

What it checks

Best use case

Main risk

===

Reference identity only

React memoization, state identity checks

Returns false for equal-looking but separate objects

Shallow compare

Top-level keys + values

Flat config objects, props optimization

Misses differences in nested objects

Deep compare

Recursive structural equality

Validation, tests, cache keys, diffing

Higher CPU cost and edge-case complexity

Pick comparison strategy based on intent and data shape.

Shallow comparison helper

Use shallow compare when object values are primitives or when nested objects are intentionally compared by reference.

JAVASCRIPT
function shallowEqual(obj1, obj2) {
  if (obj1 === obj2) return true;
  if (!obj1 || !obj2 || typeof obj1 !== 'object' || typeof obj2 !== 'object') return false;

  const keys1 = Object.keys(obj1);
  const keys2 = Object.keys(obj2);
  if (keys1.length !== keys2.length) return false;

  for (const key of keys1) {
    if (!Object.prototype.hasOwnProperty.call(obj2, key)) return false;
    if (!Object.is(obj1[key], obj2[key])) return false;
  }

  return true;
}
                  

Business case: shallow is often enough

If a filter bar stores only flat primitive fields like page, sort, and query, a shallow comparison is cheaper and easier to reason about than a recursive deep compare.

JAVASCRIPT
const prevFilters = { page: 1, sort: 'price', query: 'gpu' };
const nextFilters = { page: 1, sort: 'price', query: 'gpu' };

console.log(shallowEqual(prevFilters, nextFilters)); // true
// Good enough for a refetch guard or memo check on flat primitive fields.
                  

Deep comparison helper (handles cycles)

For nested data, deep comparison is safer. A robust helper should handle arrays, dates, and circular references.

JAVASCRIPT
function deepEqual(a, b, seen = new WeakMap()) {
  if (Object.is(a, b)) return true;

  if (typeof a !== 'object' || a === null || typeof b !== 'object' || b === null) {
    return false;
  }

  if (a.constructor !== b.constructor) return false;

  if (a instanceof Date) return a.getTime() === b.getTime();
  if (a instanceof RegExp) return String(a) === String(b);

  if (seen.get(a) === b) return true;
  seen.set(a, b);

  if (Array.isArray(a)) {
    if (!Array.isArray(b) || a.length !== b.length) return false;
    for (let i = 0; i < a.length; i++) {
      if (!deepEqual(a[i], b[i], seen)) return false;
    }
    return true;
  }

  const keysA = Object.keys(a);
  const keysB = Object.keys(b);
  if (keysA.length !== keysB.length) return false;

  for (const key of keysA) {
    if (!Object.prototype.hasOwnProperty.call(b, key)) return false;
    if (!deepEqual(a[key], b[key], seen)) return false;
  }

  return true;
}
                  
JAVASCRIPT
const x = { id: 1, meta: { tags: ['js', 'interview'] } };
const y = { id: 1, meta: { tags: ['js', 'interview'] } };

console.log(shallowEqual(x, y)); // false (nested object references differ)
console.log(deepEqual(x, y));    // true  (same nested values)
                  

Why JSON.stringify is not a universal solution

The stringify trick is fast to write, but it breaks in real systems:

  • Key order can differ between objects with same logical meaning.
  • undefined, functions, and symbols are dropped.
  • Circular references throw errors.
  • Date, Map, Set, and class instances need special handling.
JAVASCRIPT
const q1 = { sort: 'price', page: 1 };
const q2 = { page: 1, sort: 'price' };
console.log(JSON.stringify(q1) === JSON.stringify(q2)); // false

const p = { a: 1, b: undefined };
const q = { a: 1 };
console.log(JSON.stringify(p) === JSON.stringify(q)); // true
                  

Follow-up limits

  • Dates usually need value comparison such as getTime().
  • Functions usually compare by identity, not by source text.
  • Cycles require visited-pair tracking or a proven library.

Production guidance

  • Use === for identity checks (cheap and exact).
  • Use shallow compare for flat objects and render optimization.
  • Use a proven library (for example fast-deep-equal) when deep equality must be reliable and fast.
  • In tests, include edge cases: NaN, dates, arrays, functions, and circular references.

Practical scenario
A product filter panel compares previous and next query objects to decide whether to refetch results. A strict reference check misses equal-by-value objects, while naive deep checks hurt performance on every keystroke.

Common pitfalls

  • Using === when your intent is value equality.
  • Using JSON.stringify where key order, undefined, or cycles matter.
  • Running deep comparison on large objects inside hot render loops instead of using the cheapest strategy that fits the business intent.
Trade-off or test tip
Choose comparison depth by use case, then benchmark. In UI code, prefer stable object creation plus targeted shallow checks; in validation/tests, use robust deep equality.

Similar questions
Guides
Preparing for interviews?

Use this as one explanation rep, then continue with the JavaScript interview questions cluster or a guided prep path.