# fast-equals
Perform [blazing fast](#benchmarks) equality comparisons (either deep or shallow) on two objects passed, while also maintaining a high degree of flexibility for various implementation use-cases. It has no dependencies, and is ~1.8kB when minified and gzipped.
The following types are handled out-of-the-box:
- Plain objects (including `react` elements and `Arguments`)
- Arrays
- Typed Arrays
- `Date` objects
- `RegExp` objects
- `Map` / `Set` iterables
- `Promise` objects
- Primitive wrappers (`new Boolean()` / `new Number()` / `new String()`)
- Custom class instances, including subclasses of native classes
Methods are available for deep, shallow, or referential equality comparison. In addition, you can opt into support for circular objects, or performing a "strict" comparison with unconventional property definition, or both. You can also customize any specific type comparison based on your application's use-cases.
## Table of contents
- [fast-equals](#fast-equals)
- [Table of contents](#table-of-contents)
- [Usage](#usage)
- [Specific builds](#specific-builds)
- [Available methods](#available-methods)
- [deepEqual](#deepequal)
- [Comparing `Map`s](#comparing-maps)
- [shallowEqual](#shallowequal)
- [sameValueZeroEqual](#samevaluezeroequal)
- [circularDeepEqual](#circulardeepequal)
- [circularShallowEqual](#circularshallowequal)
- [strictDeepEqual](#strictdeepequal)
- [strictShallowEqual](#strictshallowequal)
- [strictCircularDeepEqual](#strictcirculardeepequal)
- [strictCircularShallowEqual](#strictcircularshallowequal)
- [createCustomEqual](#createcustomequal)
- [Recipes](#recipes)
- [Benchmarks](#benchmarks)
- [Development](#development)
## Usage
```ts
import { deepEqual } from 'fast-equals';
console.log(deepEqual({ foo: 'bar' }, { foo: 'bar' })); // true
```
### Specific builds
By default, npm should resolve the correct build of the package based on your consumption (ESM vs CommonJS). However, if you want to force use of a specific build, they can be located here:
- ESM => `fast-equals/dist/esm/index.mjs`
- CommonJS => `fast-equals/dist/cjs/index.cjs`
- UMD => `fast-equals/dist/umd/index.js`
- Minified UMD => `fast-equals/dist/min/index.js`
If you are having issues loading a specific build type, [please file an issue](https://github.com/planttheidea/fast-equals/issues).
## Available methods
### deepEqual
Performs a deep equality comparison on the two objects passed and returns a boolean representing the value equivalency of the objects.
```ts
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
```
#### Comparing `Map`s
`Map` objects support complex keys (objects, Arrays, etc.), however [the spec for key lookups in `Map` are based on `SameZeroValue`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map#key_equality). If the spec were followed for comparison, the following would always be `false`:
```ts
const mapA = new Map([[{ foo: 'bar' }, { baz: 'quz' }]]);
const mapB = new Map([[{ foo: 'bar' }, { baz: 'quz' }]]);
deepEqual(mapA, mapB);
```
To support true deep equality of all contents, `fast-equals` will perform a deep equality comparison for key and value parirs. Therefore, the above would be `true`.
### shallowEqual
Performs a shallow equality comparison on the two objects passed and returns a boolean representing the value equivalency of the objects.
```ts
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
```
### sameValueZeroEqual
Performs a [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) comparison on the two objects passed and returns a boolean representing the value equivalency of the objects. In simple terms, this means either strictly equal or both `NaN`.
```ts
import { sameValueZeroEqual } from 'fast-equals';
const mainObject = { foo: NaN, bar: 'baz' };
const objectA = 'baz';
const objectB = NaN;
const objectC = { foo: NaN, bar: 'baz' };
console.log(sameValueZeroEqual(mainObject.bar, objectA)); // true
console.log(sameValueZeroEqual(mainObject.foo, objectB)); // true
console.log(sameValueZeroEqual(mainObject, objectC)); // false
```
### circularDeepEqual
Performs the same comparison as `deepEqual` but supports circular objects. It is slower than `deepEqual`, so only use if you know circular objects are present.
```ts
function Circular(value) {
this.me = {
deeply: {
nested: {
reference: this,
},
},
value,
};
}
console.log(circularDeepEqual(new Circular('foo'), new Circular('foo'))); // true
console.log(circularDeepEqual(new Circular('foo'), new Circular('bar'))); // false
```
Just as with `deepEqual`, [both keys and values are compared for deep equality](#comparing-maps).
### circularShallowEqual
Performs the same comparison as `shallowequal` but supports circular objects. It is slower than `shallowEqual`, so only use if you know circular objects are present.
```ts
const array = ['foo'];
array.push(array);
console.log(circularShallowEqual(array, ['foo', array])); // true
console.log(circularShallowEqual(array, [array])); // false
```
### strictDeepEqual
Performs the same comparison as `deepEqual` but performs a strict comparison of the objects. In this includes:
- Checking symbol properties
- Checking non-enumerable properties in object comparisons
- Checking full descriptor of properties on the object to match
- Checking non-index properties on arrays
- Checking non-key properties on `Map` / `Set` objects
```ts
const array = [{ foo: 'bar' }];
const otherArray = [{ foo: 'bar' }];
array.bar = 'baz';
otherArray.bar = 'baz';
console.log(strictDeepEqual(array, otherArray)); // true;
console.log(strictDeepEqual(array, [{ foo: 'bar' }])); // false;
```
### strictShallowEqual
Performs the same comparison as `shallowEqual` but performs a strict comparison of the objects. In this includes:
- Checking non-enumerable properties in object comparisons
- Checking full descriptor of properties on the object to match
- Checking non-index properties on arrays
- Checking non-key properties on `Map` / `Set` objects
```ts
const array = ['foo'];
const otherArray = ['foo'];
array.bar = 'baz';
otherArray.bar = 'baz';
console.log(strictDeepEqual(array, otherArray)); // true;
console.log(strictDeepEqual(array, ['foo'])); // false;
```
### strictCircularDeepEqual
Performs the same comparison as `circularDeepEqual` but performs a strict comparison of the objects. In this includes:
- Checking `Symbol` properties on the object
- Checking non-enumerable properties in object comparisons
- Checking full descriptor of properties on the object to match
- Checking non-index properties on arrays
- Checking non-key properties on `Map` / `Set` objects
```ts
function Circular(value) {
this.me = {
deeply: {
nested: {
reference: this,
},
},
value,
};
}
const first = new Circular('foo');
Object.defineProperty(first, 'bar', {
enumerable: false,
value: 'baz',
});
const second = new Circular('foo');
Object.defineProperty(second, 'bar', {
enumerable: false,
value: 'baz',
});
console.log(circularDeepEqual(first, second)); // true
console.log(circularDeepEqual(first, new Circular('foo'))); // false
```
### strictCircularShallowEqual
Performs the same comparison as `circularShallowEqual` but performs a strict comparison of the objects. In this includes:
- Checking non-enumerable properties in object comparisons
- Checking full descriptor of properties on the object to match
- Checking non-index properties on arrays
- Checking non-key properties on `Map` / `Set` objects
```ts
const array = ['foo'];
const otherArray = ['foo'];
array.push(array);
otherArray.push(otherArray);
array.bar = 'baz';
otherArray.bar = 'baz';
console.log(circularShallowEqual(array, otherArray)); // true
console.log(circularShallowEqual(array, ['foo', array])); // false
```
### createCustomEqual
Creates a custom equality comparator that will be used on nested values in the object. Unlike `deepEqual` and `shallowEqual`, this is a factory method that receives the default options used internally, and allows you to override the defaults as needed. This is generally for extreme edge-cases, or supporting legacy environments.
The signature is as follows:
```ts
interface Cache {
delete(key: Key): boolean;
get(key: Key): Value | undefined;
set(key: Key, value: any): any;
}
interface ComparatorConfig {
areArraysEqual: TypeEqualityComparator;
areDatesEqual: TypeEqualityComparator;
areErrorsEqual: TypeEqualityComparator;
areFunctionsEqual: TypeEqualityComparator<(...args: any[]) => any, Meta>;
areMapsEqual: TypeEqualityComparator