react-fast-compare
Advanced tools
Comparing version 2.0.4 to 3.0.0-beta.1
declare module 'react-fast-compare' { | ||
const equal: (a: any, b: any) => boolean; | ||
export = equal; | ||
const exportedEqual: (a: any, b: any) => boolean | ||
export default exportedEqual | ||
} |
108
index.js
'use strict'; | ||
/* global Map:readonly, Set:readonly, ArrayBuffer:readonly */ | ||
var isArray = Array.isArray; | ||
var keyList = Object.keys; | ||
var hasProp = Object.prototype.hasOwnProperty; | ||
var hasElementType = typeof Element !== 'undefined'; | ||
var hasMap = typeof Map === 'function'; | ||
var hasSet = typeof Set === 'function'; | ||
var hasArrayBuffer = typeof ArrayBuffer === 'function'; | ||
// Note: We **don't** need `envHasBigInt64Array` in fde es6/index.js | ||
function equal(a, b) { | ||
// fast-deep-equal index.js 2.0.1 | ||
// START: fast-deep-equal es6/index.js 3.1.1 | ||
if (a === b) return true; | ||
if (a && b && typeof a == 'object' && typeof b == 'object') { | ||
var arrA = isArray(a) | ||
, arrB = isArray(b) | ||
, i | ||
, length | ||
, key; | ||
if (a.constructor !== b.constructor) return false; | ||
if (arrA && arrB) { | ||
var length, i, keys; | ||
if (Array.isArray(a)) { | ||
length = a.length; | ||
@@ -27,32 +27,70 @@ if (length != b.length) return false; | ||
if (arrA != arrB) return false; | ||
// START: Modifications: | ||
// 1. Extra `has<Type> &&` helpers in initial condition allow es6 code | ||
// to co-exist with es5. | ||
// 2. Replace `for of` with es5 compliant iteration using `for`. | ||
// Basically, take: | ||
// | ||
// ```js | ||
// for (i of a.entries()) | ||
// if (!b.has(i[0])) return false; | ||
// ``` | ||
// | ||
// ... and convert to: | ||
// | ||
// ```js | ||
// it = a.entries(); | ||
// for (i = it.next(); !i.done; i = it.next()) | ||
// if (!b.has(i.value[0])) return false; | ||
// ``` | ||
// | ||
// **Note**: `i` access switches to `i.value`. | ||
var it; | ||
if (hasMap && (a instanceof Map) && (b instanceof Map)) { | ||
if (a.size !== b.size) return false; | ||
it = a.entries(); | ||
for (i = it.next(); !i.done; i = it.next()) | ||
if (!b.has(i.value[0])) return false; | ||
it = a.entries(); | ||
for (i = it.next(); !i.done; i = it.next()) | ||
if (!equal(i.value[1], b.get(i.value[0]))) return false; | ||
return true; | ||
} | ||
var dateA = a instanceof Date | ||
, dateB = b instanceof Date; | ||
if (dateA != dateB) return false; | ||
if (dateA && dateB) return a.getTime() == b.getTime(); | ||
if (hasSet && (a instanceof Set) && (b instanceof Set)) { | ||
if (a.size !== b.size) return false; | ||
it = a.entries(); | ||
for (i = it.next(); !i.done; i = it.next()) | ||
if (!b.has(i.value[0])) return false; | ||
return true; | ||
} | ||
// END: Modifications | ||
var regexpA = a instanceof RegExp | ||
, regexpB = b instanceof RegExp; | ||
if (regexpA != regexpB) return false; | ||
if (regexpA && regexpB) return a.toString() == b.toString(); | ||
if (hasArrayBuffer && ArrayBuffer.isView(a) && ArrayBuffer.isView(b)) { | ||
length = a.length; | ||
if (length != b.length) return false; | ||
for (i = length; i-- !== 0;) | ||
if (a[i] !== b[i]) return false; | ||
return true; | ||
} | ||
var keys = keyList(a); | ||
if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags; | ||
if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf(); | ||
if (a.toString !== Object.prototype.toString) return a.toString() === b.toString(); | ||
keys = Object.keys(a); | ||
length = keys.length; | ||
if (length !== Object.keys(b).length) return false; | ||
if (length !== keyList(b).length) | ||
return false; | ||
for (i = length; i-- !== 0;) | ||
if (!hasProp.call(b, keys[i])) return false; | ||
// end fast-deep-equal | ||
if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false; | ||
// END: fast-deep-equal | ||
// start react-fast-compare | ||
// START: react-fast-compare | ||
// custom handling for DOM elements | ||
if (hasElementType && a instanceof Element && b instanceof Element) | ||
return a === b; | ||
if (hasElementType && a instanceof Element) return false; | ||
// custom handling for React | ||
for (i = length; i-- !== 0;) { | ||
key = keys[i]; | ||
var key = keys[i]; | ||
if (key === '_owner' && a.$$typeof) { | ||
@@ -64,10 +102,10 @@ // React-specific: avoid traversing React elements' _owner. | ||
continue; | ||
} else { | ||
// all other properties should be traversed as usual | ||
if (!equal(a[key], b[key])) return false; | ||
} | ||
// all other properties should be traversed as usual | ||
if (!equal(a[key], b[key])) return false; | ||
} | ||
// end react-fast-compare | ||
// END: react-fast-compare | ||
// fast-deep-equal index.js 2.0.1 | ||
// START: fast-deep-equal | ||
return true; | ||
@@ -84,3 +122,3 @@ } | ||
} catch (error) { | ||
if ((error.message && error.message.match(/stack|recursion/i)) || (error.number === -2146828260)) { | ||
if (((error.message || '').match(/stack|recursion/i)) || (error.number === -2146828260)) { | ||
// warn on circular references, don't crash | ||
@@ -87,0 +125,0 @@ // browsers give this different errors name and messages: |
{ | ||
"name": "react-fast-compare", | ||
"version": "2.0.4", | ||
"version": "3.0.0-beta.1", | ||
"description": "Fastest deep equal comparison for React. Perfect for shouldComponentUpdate. Also really fast general-purpose deep comparison", | ||
"main": "index.js", | ||
"scripts": { | ||
"preversion": "npm run test", | ||
"preversion": "yarn test", | ||
"benchmark": "node benchmark", | ||
@@ -13,6 +13,8 @@ "eslint": "eslint \"*.js\" benchmark test", | ||
"test-node": "mocha \"test/node/*.spec.js\"", | ||
"test-node-cov": "nyc npm run test-node", | ||
"test-node-cov": "nyc yarn test-node", | ||
"test-ts": "tsc --target ES5 --noImplicitAny index.d.ts", | ||
"test": "builder concurrent --buffer eslint test-ts test-node-cov test-browser", | ||
"test-ie": "builder concurrent --buffer eslint test-ts test-node-cov test-browser-ie" | ||
"test-ie": "builder concurrent --buffer eslint test-ts test-node-cov test-browser-ie", | ||
"compress": "terser --compress --mangle=\"toplevel:true\" -- index.js", | ||
"size-min-gz": "yarn -s compress | gzip -9 | wc -c" | ||
}, | ||
@@ -38,13 +40,14 @@ "repository": { | ||
"devDependencies": { | ||
"babel-core": "^6.26.0", | ||
"babel-loader": "^7.1.4", | ||
"babel-preset-env": "^1.6.1", | ||
"@babel/core": "^7.7.5", | ||
"@babel/preset-env": "^7.7.6", | ||
"babel-loader": "^8.0.6", | ||
"benchmark": "^2.1.4", | ||
"builder": "^4.0.0", | ||
"core-js": "^2.5.5", | ||
"coveralls": "^2.13.1", | ||
"eslint": "^4.0.0", | ||
"fast-deep-equal": "2.0.1", | ||
"karma": "^2.0.0", | ||
"karma-chrome-launcher": "^2.2.0", | ||
"builder": "^5.0.0", | ||
"core-js": "^3.5.0", | ||
"coveralls": "^3.0.9", | ||
"eslint": "^6.7.2", | ||
"fast-deep-equal": "3.1.1", | ||
"fast-deep-equal-git": "epoberezkin/fast-deep-equal#v3.1.1", | ||
"karma": "^4.4.1", | ||
"karma-chrome-launcher": "^3.1.0", | ||
"karma-firefox-launcher": "^1.1.0", | ||
@@ -55,12 +58,13 @@ "karma-ie-launcher": "^1.0.0", | ||
"karma-safari-launcher": "^1.0.0", | ||
"karma-webpack": "^3.0.0", | ||
"karma-webpack": "^4.0.2", | ||
"lodash": "^4.17.10", | ||
"mocha": "^3.4.2", | ||
"mocha": "^6.2.2", | ||
"nano-equal": "^2.0.2", | ||
"nyc": "^11.0.2", | ||
"nyc": "^14.1.1", | ||
"react": "^16.3.1", | ||
"react-test-renderer": "^16.3.1", | ||
"shallow-equal-fuzzy": "0.0.2", | ||
"sinon": "^4.5.0", | ||
"typescript": "^2.6.1", | ||
"sinon": "^7.5.0", | ||
"terser": "^4.4.3", | ||
"typescript": "^3.7.3", | ||
"webpack": "^4.5.0" | ||
@@ -67,0 +71,0 @@ }, |
# react-fast-compare | ||
[![Downloads][downloads_img]][npm_site] | ||
[![size_minzip][size_minzip]][size_site] | ||
[![Travis Status][trav_img]][trav_site] | ||
[![AppVeyor Status][appveyor_img]][appveyor_site] | ||
[![npm version][npm_img]][npm_site] | ||
[![Maintenance Status][maintenance-image]](#maintenance-status) | ||
The fastest deep equal comparison for React. Really fast general-purpose deep comparison. | ||
Great for`shouldComponentUpdate`. This is a fork of the brilliant | ||
Great for `shouldComponentUpdate`. This is a fork of the brilliant | ||
[fast-deep-equal](https://github.com/epoberezkin/fast-deep-equal) with some | ||
extra handling for React. | ||
[![Travis Status][trav_img]][trav_site] | ||
[![AppVeyor Status][appveyor_img]][appveyor_site] | ||
[![npm version][npm_img]][npm_site] | ||
[![size_minzip][size_minzip]][size_site] | ||
[![size_min][size_min]][size_site] | ||
![benchmark chart](assets/benchmarking.png "benchmarking chart") | ||
@@ -28,8 +29,8 @@ | ||
* ES5 compatible; works in node.js (0.10+) and browsers (IE9+) | ||
* deeply compares any value (besides objects with circular references) | ||
* handles React-specific circular references, like elements | ||
* checks equality Date and RegExp objects | ||
* should be just as fast as [fast-deep-equal](https://github.com/epoberezkin/fast-deep-equal) for general use, and faster for React use | ||
* small: under 600 bytes minified+gzipped | ||
- ES5 compatible; works in node.js (0.10+) and browsers (IE9+) | ||
- deeply compares any value (besides objects with circular references) | ||
- handles React-specific circular references, like elements | ||
- checks equality Date and RegExp objects | ||
- should as fast as [fast-deep-equal](https://github.com/epoberezkin/fast-deep-equal) via a single unified library, and with added guardrails for circular references. | ||
- small: under 700 bytes minified+gzipped | ||
@@ -79,3 +80,3 @@ ## Usage | ||
Benchmarking source can be found | ||
[here](https://github.com/FormidableLabs/react-fast-compare/blob/master/node/tests.js). | ||
[here](https://github.com/FormidableLabs/react-fast-compare/blob/master/benchmark/index.js). | ||
Each "operation" consists of running all relevant tests. The React benchmark | ||
@@ -88,7 +89,7 @@ uses both the generic tests and the react tests; these runs will be slower | ||
``` | ||
react-fast-compare x 207,503 ops/sec ±0.54% (92 runs sampled) | ||
fast-deep-equal x 195,006 ops/sec ±0.70% (91 runs sampled) | ||
lodash.isEqual x 43,778 ops/sec ±0.55% (91 runs sampled) | ||
nano-equal x 198,036 ops/sec ±0.37% (95 runs sampled) | ||
shallow-equal-fuzzy x 173,023 ops/sec ±0.59% (95 runs sampled) | ||
react-fast-compare x 157,863 ops/sec ±0.54% (94 runs sampled) | ||
fast-deep-equal x 149,877 ops/sec ±0.76% (93 runs sampled) | ||
lodash.isEqual x 33,298 ops/sec ±0.70% (93 runs sampled) | ||
nano-equal x 144,836 ops/sec ±0.51% (94 runs sampled) | ||
shallow-equal-fuzzy x 110,192 ops/sec ±0.57% (95 runs sampled) | ||
fastest: react-fast-compare | ||
@@ -104,12 +105,10 @@ ``` | ||
``` | ||
react-fast-compare x 187,628 ops/sec ±0.58% (93 runs sampled) | ||
fast-deep-equal x 477 ops/sec ±0.55% (91 runs sampled) | ||
lodash.isEqual x 35,100 ops/sec ±0.16% (95 runs sampled) | ||
nano-equal x 468 ops/sec ±0.53% (94 runs sampled) | ||
shallow-equal-fuzzy x 684 ops/sec ±0.43% (92 runs sampled) | ||
fastest: react-fast-compare | ||
react-fast-compare x 64,102 ops/sec ±0.36% (94 runs sampled) | ||
fast-deep-equal x 63,844 ops/sec ±0.43% (94 runs sampled) | ||
lodash.isEqual x 6,243 ops/sec ±0.72% (90 runs sampled) | ||
fastest: react-fast-compare,fast-deep-equal | ||
``` | ||
Three of these packages cannot handle comparing React elements (which are | ||
circular): `fast-deep-equal`, `nano-equal`, and `shallow-equal-fuzzy`. | ||
Two of these packages cannot handle comparing React elements, because they | ||
contain circular reference: `nano-equal` and `shallow-equal-fuzzy`. | ||
@@ -125,4 +124,9 @@ ### Running Benchmarks | ||
react-fast-compare@2.0.0 tracks fast-deep-equal@2.0.1 | ||
react-fast-compare@3 tracks fast-deep-equal@3.1.1 | ||
Now that `fast-deep-equal` has separate es5, es6, and es6 + React entry points, the main differences with this library are: | ||
- `try/catch` guardrails for stack overflows from undetected circular references. | ||
- A single unified entry point for **all** uses. No matter what your target application is, `import equal from 'react-fast-compare'` just works. | ||
## License | ||
@@ -136,4 +140,8 @@ | ||
[trav_img]: https://api.travis-ci.org/FormidableLabs/react-fast-compare.svg | ||
[trav_site]: https://travis-ci.org/FormidableLabs/react-fast-compare | ||
## Maintenance Status | ||
**Active:** Formidable is actively working on this project, and we expect to continue for work for the foreseeable future. Bug reports, feature requests and pull requests are welcome. | ||
[trav_img]: https://api.travis-ci.com/FormidableLabs/react-fast-compare.svg | ||
[trav_site]: https://travis-ci.com/FormidableLabs/react-fast-compare | ||
[cov_img]: https://img.shields.io/coveralls/FormidableLabs/react-fast-compare.svg | ||
@@ -148,1 +156,3 @@ [cov_site]: https://coveralls.io/r/FormidableLabs/react-fast-compare | ||
[size_site]: https://bundlephobia.com/result?p=react-fast-compare | ||
[downloads_img]: https://img.shields.io/npm/dt/react-fast-compare.svg | ||
[maintenance-image]: https://img.shields.io/badge/maintenance-active-green.svg |
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
15695
6
119
152
29
1