Toggle navigation
MeasureThat.net
Create a benchmark
Tools
Feedback
FAQ
Register
Log In
Run results for:
Lodash isEqual vs fast-is-equal vs JSON.stringify vs fast-deep-equal
Go to the benchmark
Embed
Embed Benchmark Result
Run details:
User agent:
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36
Browser:
Chrome 139
Operating system:
Mac OS X 10.15.7
Device Platform:
Desktop
Date tested:
8 months ago
Test name
Executions per second
_.isEqual Level 1
3712189.8 Ops/sec
deepEquals Level 1
76328336.0 Ops/sec
JSON.stringify Level 1
5818422.0 Ops/sec
fast-deep-equal Level 1
5129191.0 Ops/sec
HTML Preparation code:
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.4/lodash.min.js"></script> <script> // https://github.com/epoberezkin/fast-deep-equal // https://cdn.jsdelivr.net/npm/fast-deep-equal@3.1.3 function fastDeepEquals(t, e) { if (t === e) return !0; if (t && e && "object" == typeof t && "object" == typeof e) { if (t.constructor !== e.constructor) return !1; var o, n, u; if (Array.isArray(t)) { if ((o = t.length) != e.length) return !1; for (n = o; 0 != n--;) if (! fastDeepEquals(t[n], e[n])) return !1; return !0 } if (t.constructor === RegExp) return t.source === e.source && t.flags === e.flags; if (t.valueOf !== Object.prototype.valueOf) return t.valueOf() === e.valueOf(); if (t.toString !== Object.prototype.toString) return t.toString() === e.toString(); if ((o =( u = Object.keys(t)).length) !== Object.keys(e).length) return !1; for (n = o; 0 != n--;) if (!Object .prototype .hasOwnProperty .call(e, u[n])) return !1; for (n = o; 0 != n--;) { var f = u[n]; if (! fastDeepEquals(t[f], e[f])) return !1 } return !0 } return t != t && e != e } // https://github.com/JairajJangle/fast-is-equal // https://cdn.jsdelivr.net/npm/fast-is-equal@1.2.3 const TYPEOF_OBJECT = "object", TYPEOF_FUNCTION = "function", TYPEOF_NUMBER = "number", TYPEOF_STRING = "string", TYPEOF_BOOLEAN = "boolean", TYPEOF_SYMBOL = "symbol", TYPEOF_BIGINT = "bigint", isNaN = Number.isNaN, dateConstructor = Date, regExpConstructor = RegExp, mapConstructor = Map, setConstructor = Set, arrayBufferConstructor = ArrayBuffer, promiseConstructor = Promise, errorConstructor = Error, dataViewConstructor = DataView; function fastIsEqual(t, r) { if (t === r) return !0; if (null == t || null == r) return !1; const e = typeof t; if ("number" === e) return "number" == typeof r && isNaN(t) && isNaN(r); if ("string" === e || "boolean" === e || "function" === e || "symbol" === e || "bigint" === e) return !1; if ("object" != typeof r) return !1; const n = Array.isArray(t); if (n !== Array.isArray(r)) return !1; const o = t.constructor; if (o !== r.constructor) return !1; if (n) { const e = t.length; if (e !== r.length) return !1; if (0 === e) return !0; if (e < 8) { for (let n = 0; n < e; n++) { const e = n in t; if (e !== n in r) return !1; if (! e) continue; const o = t[n], i = r[n]; if (o === i) continue; if (null == o || null == i) return !1; const f = typeof o; if (f !== typeof i) return !1; if ("number" !== f) { if ("object" !== f && "function" !== f) return !1; if (!deepEqual(o, i, new Map)) return !1 } else if (! isNaN(o) || ! isNaN(i)) return !1 } return !0 } return deepEqual(t, r, new Map) } return o === dateConstructor ? t.getTime() === r.getTime() : o === regExpConstructor ? t.source === r.source && t.flags === r.flags : deepEqual(t, r, new Map) } function deepEqual(t, r, e) { if (t === r) return !0; if (null == t || null == r) return !1; const n = typeof t; if (n !== typeof r) return !1; if ("number" === n) return isNaN(t) && isNaN(r); if ("object" !== n && "function" !== n) return !1; const o = e.get(t); if (void 0 !== o) return o === r; if (e.has(r)) return !1; const i = t.constructor; if (i !== r.constructor) return !1; if (i === dateConstructor) return t.getTime() === r.getTime(); if (i === regExpConstructor) return t.source === r.source && t.flags === r.flags; if (i === promiseConstructor || i === errorConstructor) return !1; if (Array.isArray(t)) { const n = t.length; if (n !== r.length) return !1; if (e.set(t, r), e.set(r, t), 0 === n) return !0; for (let o = 0; o < n; o++) { const n = o in t; if (n !== o in r) return !1; if (! n) continue; const i = t[o], f = r[o]; if (i !== f && ! deepEqual(i, f, e)) return !1 } return !0 } if (i === mapConstructor) { const n = t, o = r; if (n.size !== o.size) return !1; if (0 === n.size) return !0; e.set(t, r), e.set(r, t); for (const [t, r] of n) { const n = typeof t; if ("object" !== n && "function" !== n) { if (! o.has(t)) return !1; const n = o.get(t); if (r !== n && ! deepEqual(r, n, e)) return !1 } else { let n = !1; for (const [i, f] of o) if (deepEqual(t, i, e) && deepEqual(r, f, e)) { n = !0; break } if (! n) return !1 } } return !0 } if (i === setConstructor) { const n = t, o = r; if (n.size !== o.size) return !1; if (0 === n.size) return !0; e.set(t, r), e.set(r, t); let i = !1, f = !1; for (const t of n) { const r = typeof t; if ("object" === r || "function" === r) f = !0; else if (i =! 0, ! o.has(t)) return !1 } if (! f) return !0; const u = [], s = []; for (const t of n) { const r = typeof t; "object" !== r && "function" !== r || u.push(t) } for (const t of o) { const r = typeof t; "object" !== r && "function" !== r || s.push(t) } const c = new Uint8Array(s.length); for (const t of u) { let r = !1; for (let n = 0; n < s.length; n++) if (! c[n]) { const o = new Map(e); if (deepEqual(t, s[n], o)) { c[n] = 1, r = !0; break } } if (! r) return !1 } return !0 } if (i === arrayBufferConstructor) { const e = t, n = r, o = e.byteLength; if (o !== n.byteLength) return !1; const i = new Uint8Array(e), f = new Uint8Array(n); let u = 0; const s = o - 7; for (; u < s; u += 8) if (i[u] !== f[u] || i[u + 1] !== f[u + 1] || i[u + 2] !== f[u + 2] || i[u + 3] !== f[u + 3] || i[u + 4] !== f[u + 4] || i[u + 5] !== f[u + 5] || i[u + 6] !== f[u + 6] || i[u + 7] !== f[u + 7]) return !1; for (; u < o; u++) if (i[u] !== f[u]) return !1; return !0 } if (i === dataViewConstructor) { const e = t, n = r; if (e.byteLength !== n.byteLength || e.byteOffset !== n.byteOffset) return !1; for (let t = 0; t < e.byteLength; t++) if (e.getUint8(t) !== n.getUint8(t)) return !1; return !0 } if (ArrayBuffer.isView(t)) { if (t.constructor !== r.constructor) return !1; const e = t, n = r, o = e.length; if (o !== n.length) return !1; if (o < 16) { for (let t = 0; t < o; t++) if (e[t] !== n[t]) return !1; return !0 } let i = 0; const f = o - 3; for (; i < f; i += 4) if (e[i] !== n[i] || e[i + 1] !== n[i + 1] || e[i + 2] !== n[i + 2] || e[i + 3] !== n[i + 3]) return !1; for (; i < o; i++) if (e[i] !== n[i]) return !1; return !0 } e.set(t, r), e.set(r, t); const f = Object.keys(t), u = f.length; if (u !== Object.keys(r).length) return !1; if (0 === u) { if (void 0 !== Object.getOwnPropertySymbols) { const n = Object.getOwnPropertySymbols(t); if (n.length !== Object.getOwnPropertySymbols(r).length) return !1; for (let o = 0; o < n.length; o++) { const i = n[o]; if (!(i in r) || ! deepEqual(t[i], r[i], e)) return !1 } } return !0 } for (let n = 0; n < u; n++) { const o = f[n]; if (!(o in r)) return !1; const i = t[o], u = r[o]; if (i !== u) { const t = typeof i; if ("object" === t || "function" === t) { if (! deepEqual(i, u, e)) return !1 } else { if ("number" !== t) return !1; if (! isNaN(i) || ! isNaN(u)) return !1 } } } if (void 0 !== Object.getOwnPropertySymbols) { const n = Object.getOwnPropertySymbols(t); if (n.length > 0) { if (n.length !== Object.getOwnPropertySymbols(r).length) return !1; for (let o = 0; o < n.length; o++) { const i = n[o]; if (!(i in r) || ! deepEqual(t[i], r[i], e)) return !1 } } } return !0 } </script>
Script Preparation code:
// 1 level deep window.foo1 = { a: 1, b: 2, c: { a: 1, b: 2, c: { a: 1, b: 2 } } }; window.bar1 = { a: 1, b: 3, c: { a: 1, b: 2, c: { a: 1, b: 2 } } }; // 2 levels deep window.foo2 = { a: 1, b: 2, c: { a: 1, b: 2, c: { a: 1, b: 2 } } }; window.bar2 = { a: 1, b: 2, c: { a: 1, b: 3, c: { a: 1, b: 2 } } }; // 3 levels deep window.foo3 = { a: 1, b: 2, c: { a: 1, b: 2, c: { a: 1, b: 2 } } }; window.bar3 = { a: 1, b: 2, c: { a: 1, b: 2, c: { a: 1, b: 4 } } };
Tests:
_.isEqual Level 1
_.isEqual(window.foo1, window.bar1)
fast-is-equal Level 1
fastIsEqual(window.foo1, window.bar1);
JSON.stringify Level 1
JSON.stringify(window.foo1) === JSON.stringify(window.bar1);
fast-deep-equal Level 1
fastDeepEquals(window.foo1, window.bar1);
_.isEqual Level 2
_.isEqual(window.foo2, window.bar2)
fast-is-equal Level 2
fastIsEqual(window.foo2, window.bar2);
JSON.stringify Level 2
JSON.stringify(window.foo2) === JSON.stringify(window.bar2);
fast-deep-equal Level 2
fastDeepEquals(window.foo2, window.bar2);
_.isEqual Level 3
_.isEqual(window.foo3, window.bar3)
fast-is-equal Level 3
fastIsEqual(window.foo3, window.bar3);
JSON.stringify Level 3
JSON.stringify(window.foo3) === JSON.stringify(window.bar3);
fast-deep-equal Level 3
fastDeepEquals(window.foo3, window.bar3);