JavaScript Basics: Compare Nested Values with isDeepStrictEqual
Two objects can hold equivalent values without being the same object. Node’s isDeepStrictEqual provides a Boolean comparison using deep strict rules. A small set of cases shows why the intended equality contract matters.
Prepare a scratch directory
Tested on Linux with Node.js v24.19.0. You need the named runtime, Bash, a text editor, and the standard mktemp, rm, and rmdir utilities. The .mjs extension selects ES modules. Assertions check the demonstrated behavior; no npm packages or remote services are needed.
Keep using the same terminal. Stop if setup fails, before saving the source:
start_dir="$PWD"
work_dir="$(mktemp -d)" || exit 1
cd -- "$work_dir" || exit 1Run the example
Save this as demonstrate-deep-strict-equal.mjs:
import assert from 'node:assert/strict';
import { isDeepStrictEqual } from 'node:util';
const left = { labels: ['draft'], count: 2 };
const right = { count: 2, labels: ['draft'] };
assert.equal(left === right, false);
assert.equal(isDeepStrictEqual(left, right), true);
console.log('Same object identity:', left === right);
console.log('Equivalent nested values:', isDeepStrictEqual(left, right));
assert.equal(isDeepStrictEqual({ count: 2 }, { count: '2' }), false);
console.log('Number equals numeric string:', isDeepStrictEqual({ count: 2 }, { count: '2' }));
assert.equal(isDeepStrictEqual(new Set([1, 2]), new Set([2, 1])), true);
assert.equal(isDeepStrictEqual([1, 2], [2, 1]), false);
console.log('Set insertion order ignored:', isDeepStrictEqual(new Set([1, 2]), new Set([2, 1])));
console.log('Array order ignored:', isDeepStrictEqual([1, 2], [2, 1]));
const plain = { value: 1 };
const noPrototype = Object.assign(Object.create(null), { value: 1 });
assert.equal(isDeepStrictEqual(plain, noPrototype), false);
console.log('Different prototypes equal by default:', isDeepStrictEqual(plain, noPrototype));Run it:
node demonstrate-deep-strict-equal.mjsObserved output:
Same object identity: false
Equivalent nested values: true
Number equals numeric string: false
Set insertion order ignored: true
Array order ignored: false
Different prototypes equal by default: falseRead the result
Property insertion order does not change equality for these ordinary object properties, but value types still matter. A Set’s insertion order does not define its equality here, while an Array’s element order does. Default comparison also considers prototypes, so an ordinary object and a null-prototype object are not equal merely because their enumerable data looks alike.
Apply it carefully
Use the equality relation that matches your application: deep strict equality is not identity, canonical serialization, or a domain-specific comparison such as case-insensitive text equality. It is also not constant-time comparison for secrets. Complex objects, accessors, and proxies can have behavior beyond plain data; do not assume comparing arbitrary untrusted objects is side-effect-free or cheap. This article uses the default two-argument API on the tested Node version.
The official reference describes the API and its options. The checks above cover the specific fixture, not every possible input or environment.
Clean up
Remove the source and then the empty practice directory:
rm -- demonstrate-deep-strict-equal.mjs
cd -- "$start_dir" || exit 1
rmdir -- "$work_dir"
unset start_dir work_dirIf the directory is not empty, inspect the remaining files rather than deleting unknown contents.
Acknowledgements
This post was created with assistance from AI.