Perform blazing fast equality comparisons (either deep or shallow) on two objects passed. It has no dependencies, and is ~1.1Kb when minified and gzipped.
Unlike most equality validation libraries, the following types are handled out-of-the-box:
NaN
Date
objectsRegExp
objectsMap
/Set
iterables
You can also create a custom nested comparator, for specific scenarios (see below).
You can either import the full object:
import fe from 'fast-equals';
console.log(fe.deep({foo: 'bar'}, {foo: 'bar'})); // true
Or the individual imports desired:
import {deepEqual} from 'fast-equals';
console.log(deepEqual({foo: 'bar'}, {foo: 'bar'})); // true
Aliased on the default export as fe.deep
Performs a deep equality comparison on the two objects passed and returns a boolean representing the value equivalency of the objects.
import {deepEqual} from 'fast-equals';
const objectA = {foo: {bar: 'baz'}};
const objectB = {foo: {bar: 'baz'}};
console.log(objectA === objectB); // false
console.log(deepEqual(objectA, objectB)); // true
Aliased on the default export as fe.shallow
Performs a shallow equality comparison on the two objects passed and returns a boolean representing the value equivalency of the objects.
import {shallowEqual} from 'fast-equals';
const nestedObject = {bar: 'baz'};
const objectA = {foo: nestedObject};
const objectB = {foo: nestedObject};
const objectC = {foo: {bar: 'baz'}};
console.log(objectA === objectB); // false
console.log(shallowEqual(objectA, objectB)); // true
console.log(shallowEqual(objectA, objectC)); // false
Aliased on the default export as fe.createCustom
Creates a custom equality comparator that will be used on nested values in the object. Unlike deepEqual
and shallowEqual
, this is a partial-application function that will receive the internal comparator and should return a function that compares two objects.
A common use case for this is to handle circular objects (which fast-equals
does not handle by default). Example:
import {createCustomEqual} from 'fast-equals';
import decircularize from 'decircularize';
const isDeepEqualCircular = createCustomEqual((comparator) => {
return (objectA, objectB) => {
return comparator(decircularize(objectA), decircularize(objectB));
};
});
const objectA = {};
const objectB = {};
objectA.a = objectA;
objectA.b = objectB;
objectB.a = objectA;
objectB.b = objectB;
console.log(isDeepEqualCircular(objectA, objectB)); // true
All benchmarks are based on averages of running comparisons based on the following data types:
- Primitives (
String
,Number
,null
,undefined
) Function
sObject
sArray
sDate
sRegExp
s- A mixed object with a combination of all the above types
Operations / second | Relative margin of error | |
---|---|---|
fast-equals | 197,615 | 0.53% |
nano-equal | 121.843 | 0.49% |
fast-deep-equal | 102,257 | 0.41% |
shallow-equal-fuzzy | 80,224 | 0.55% |
underscore.isEqual | 51,110 | 0.52% |
deep-equal | 32,907 | 0.82% |
lodash.isEqual | 26,021 | 0.48% |
deep-eql | 14,589 | 0.66% |
assert.deepStrictEqual | 441 | 1.39% |
Caveats that impact the benchmark:
fast-deep-equal
does not supportNaN
orSameValueZero
equality for datesnano-equal
does not strictly compare object property structure, array length, or object type, norSameValueZero
equality for datesshallow-equal-fuzzy
does not strictly compare object type or regexp values, norSameValueZero
equality for datesunderscore.isEqual
does not supportSameValueZero
equality for primitives or datesdeep-equal
does not supportNaN
and does not strictly compare object type, or date / regexp values, nor usesSameValueZero
equality for datesdeep-eql
does not supportSameValueZero
equality for zero equality (positive and negative zero are not equal)assert.deepStrictEqual
does not supportNaN
orSameValueZero
equality for dates
All of these have the potential of inflating the respective library's numbers in comparison to fast-equals
, but it was the closest apples-to-apples comparison I could create of a reasonable sample size. Map
s and Set
s were excluded from the benchmark entirely because no library other than lodash
supported their comparison.
Standard practice, clone the repo and npm i
to get the dependencies. The following npm scripts are available:
- benchmark => run benchmark tests against other equality libraries
- build => build unminified dist version with source map and NODE_ENV=development via webpack
- build:minified => build minified dist version with NODE_ENV=production via webpack
- clean => run
clean:dist
,clean:es
, andclean:lib
scripts - clean:dist => run
rimraf
on thedist
folder - clean:es => run
rimraf
on thees
folder - clean:lib => run
rimraf
on thelib
folder - dev => start webpack playground App
- dist => run
build
andbuild:minified
scripts - lint => run ESLint on all files in
src
folder (also runs ondev
script) - lint:fix => run
lint
script, but with auto-fixer - prepublish =>
- prepublish:compile => run
lint
,test:coverage
,transpile:lib
,transpile:es
, anddist
scripts - start => run
dev
- test => run AVA with NODE_ENV=test on all files in
test
folder - test:coverage => run same script as
test
with code coverage calculation vianyc
- test:watch => run same script as
test
but keep persistent watcher - transpile:es => run Babel on all files in
src
folder (transpiled toes
folder without transpilation of ES2015 export syntax) - transpile:lib => run Babel on all files in
src
folder (transpiled tolib
folder)