Object Equality in JavaScript: {} isn't Equal to {}

I admit, this is one of my go‑to interview questions when looking to hire new front‑end developers into one of my teams (something that I've been doing a lot of recently). The question is simple. Given the code below, can you explain why a == b will return false?
let a = {};
let b = {};On the surface of this, it does seem like both a and b should be equal. I tend to find that it is around 50‑50 whether an interviewee understands the reason behind why these two empty objects aren't equal. It also helpfully tends to identify those candidates whose experience lies more in relying on helpers and frameworks rather than understanding the more fundamental aspects of JavaScript and data types.
Understanding Object Identity
The answer to this question lies in how JavaScript handles object comparison. When comparing objects, JavaScript doesn't look at their contents or structure (as it might do with an equality operator on a simple number, boolean, or string variable). Instead, it looks at the object identities ‑ it checks if the objects being compared are exactly the same instance.
In our example, a and b are different objects, each with their own unique references within memory. Even though they have the same structure and content (i.e., empty), they are considered distinct entities within the JavaScript engine. This is a fairly fundamental concept which underpins a lot of JavaScript's behaviour when it comes to objects and their comparison.
Deep Comparison for Objects
If you are ever asked this question in an interview and really want to earn a few extra points, then being able to explain how you would compare two objects (and their contents) would certainly achieve that. JavaScript doesn't offer a built‑in operator for this, but that doesn't mean that it's particularly difficult or a dead end.
You can perform a deep comparison by writing a function that iteratively checks each property and value within the objects or by using utilities provided by libraries like Lodash, which offer methods specifically designed for this purpose.
In JavaScript
For arrays and plain objects, this helper compares the values at each own key. It allows cyclic references and treats shared references as equivalent to separate objects with the same contents; it isn't checking whether two object graphs share the same pattern of identities.
const deepEqualPlainData = (left, right, seen = new WeakMap()) => {
if (left === right) return true;
if (
typeof left !== 'object' || left === null ||
typeof right !== 'object' || right === null
) {
return false;
}
const leftPrototype = Object.getPrototypeOf(left);
const rightPrototype = Object.getPrototypeOf(right);
const isSupported = Array.isArray(left) ||
leftPrototype === Object.prototype || leftPrototype === null;
if (!isSupported || leftPrototype !== rightPrototype ||
Array.isArray(left) !== Array.isArray(right)) return false;
if (seen.get(left)?.has(right)) return true;
if (!seen.has(left)) seen.set(left, new WeakSet());
seen.get(left).add(right);
const leftKeys = Reflect.ownKeys(left);
const rightKeys = Reflect.ownKeys(right);
if (leftKeys.length !== rightKeys.length) return false;
for (const key of leftKeys) {
if (!Object.prototype.hasOwnProperty.call(right, key)) return false;
if (!deepEqualPlainData(left[key], right[key], seen)) return false;
}
return true;
};
const obj1 = { a: 1, b: { c: 1 } };
const obj2 = { a: 1, b: { c: 1 } };
console.log(deepEqualPlainData(obj1, obj2)); //=> true
const obj3 = { a: 1, b: { c: 2 } };
console.log(deepEqualPlainData(obj1, obj3)); //=> falseThe helper uses strict equality for primitive values and compares all own keys, including symbols. A WeakMap of WeakSet instances records pairs already being compared so cycles terminate. Matching prototypes are required. Distinct Date, RegExp, Map, Set and class instances need type‑specific handling or a library. This is for ordinary data: getters and proxies can execute code when their properties are read.
Using Lodash
Alternatively, if you prefer using a library (or if you already have Lodash as a dependency in your project), then the isEqual method will already do this for you:
import isEqual from 'lodash/isEqual';
const obj1 = { a: 1, b: { c: 1 } };
const obj2 = { a: 1, b: { c: 1 } };
console.log(isEqual(obj1, obj2)); //=> trueWrapping Up
Although comparing {} with {} and getting false might feel counterintuitive, this is an area that unveils a candidate's understanding of JavaScript's approach to object identity and comparison. Although only a tiny piece of what makes a good developer, this is a concept that is really important when it comes to writing efficient and optimised code. In the realm of objects in JavaScript, identity precedes equality.