Skip to content

Commit

Permalink
is-shallow-equal: Fall back to strict equality for non-object-like (#116
Browse files Browse the repository at this point in the history
)

* Ensure inverse argument order has same test result

* is-shallow-equal: Fall back to strict equality for non-object-like

* is-shallow-equal: De-snark README.md
  • Loading branch information
aduth authored May 1, 2018
1 parent ee842ec commit e83cca2
Show file tree
Hide file tree
Showing 6 changed files with 168 additions and 126 deletions.
101 changes: 55 additions & 46 deletions packages/is-shallow-equal/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,68 +36,77 @@ Shallow equality utilities are already a dime a dozen. Since these operations ar
In particular, it should…

1. …consider non-primitive yet referentially-equal members values as equal.
- Sorry, [`is-equal-shallow`](https://www.npmjs.com/package/is-equal-shallow).
- Eliminates [`is-equal-shallow`](https://www.npmjs.com/package/is-equal-shallow) as an option.
2. …offer a single function through which to interface, regardless of value type.
- Sorry, [`shallow-equal`](https://www.npmjs.com/package/shallow-equal).
- Eliminates [`shallow-equal`](https://www.npmjs.com/package/shallow-equal) as an option.
3. …be barebones; only providing the basic functionality of shallow equality.
- Sorry, [`shallow-equals`](https://www.npmjs.com/package/shallow-equals).
4. …be intended for use in non-Facebook projects.
- Sorry, [`fbjs/lib/shallowEqual`](https://www.npmjs.com/package/fbjs).
5. …be the fastest implementation.
- Sorry, _every other solution_.
- Eliminates [`shallow-equals`](https://www.npmjs.com/package/shallow-equals) as an option.
4. …anticipate and optimize for referential sameness as equal.
- Eliminates [`is-equal-shallow`](https://www.npmjs.com/package/is-equal-shallow) and [`shallow-equals`](https://www.npmjs.com/package/shallow-equals) as options.
5. …be intended for use in non-Facebook projects.
- Eliminates [`fbjs/lib/shallowEqual`](https://www.npmjs.com/package/fbjs) as an option.
6. …be the most performant implementation.
- See [Benchmarks](#benchmarks).

## Benchmarks

The following results were produced under Node v9.10.1 on a MacBook Pro (Late 2016) 2.9 GHz Intel Core i7. The winner of each category is shown in bold.
The following results were produced under Node v8.11.1 (LTS) on a MacBook Pro (Late 2016) 2.9 GHz Intel Core i7.

>**@wordpress/is-shallow-equal (object, equal) x 4,737,184 ops/sec ±0.41% (90 runs sampled)**
>**@wordpress/is-shallow-equal (object, same) x 529,764,894 ops/sec ±0.61% (90 runs sampled)**
>**@wordpress/is-shallow-equal (object, unequal) x 4,925,046 ops/sec ±0.55% (92 runs sampled)**
>**@wordpress/is-shallow-equal (array, equal) x 65,801,336 ops/sec ±0.47% (90 runs sampled)**
>**@wordpress/is-shallow-equal (array, same) x 540,194,917 ops/sec ±0.39% (93 runs sampled)**
>**@wordpress/is-shallow-equal (array, unequal) x 35,380,873 ops/sec ±0.91% (89 runs sampled)**
>`@wordpress/is-shallow-equal (type specific) (object, equal) x 4,902,162 ops/sec ±0.40% (89 runs sampled)`
>`@wordpress/is-shallow-equal (type specific) (object, same) x 558,234,287 ops/sec ±0.28% (92 runs sampled)`
>`@wordpress/is-shallow-equal (type specific) (object, unequal) x 5,062,890 ops/sec ±0.71% (90 runs sampled)`
>`@wordpress/is-shallow-equal (type specific) (array, equal) x 70,419,519 ops/sec ±0.56% (86 runs sampled)`
>`@wordpress/is-shallow-equal (type specific) (array, same) x 561,159,444 ops/sec ±0.33% (91 runs sampled)`
>`@wordpress/is-shallow-equal (type specific) (array, unequal) x 37,299,061 ops/sec ±0.89% (86 runs sampled)`
>
>shallowequal (object, equal) x 3,290,410 ops/sec ±0.36% (93 runs sampled)
>shallowequal (object, same) x 470,354,546 ops/sec ±0.61% (90 runs sampled)
>shallowequal (object, unequal) x 3,552,560 ops/sec ±0.49% (92 runs sampled)
>shallowequal (array, equal) x 1,499,613 ops/sec ±0.33% (90 runs sampled)
>shallowequal (array, same) x 470,952,874 ops/sec ±0.36% (90 runs sampled)
>shallowequal (array, unequal) x 1,518,756 ops/sec ±0.38% (93 runs sampled)
>`@wordpress/is-shallow-equal (object, equal) x 4,449,938 ops/sec ±0.34% (91 runs sampled)`
>`@wordpress/is-shallow-equal (object, same) x 516,101,448 ops/sec ±0.64% (90 runs sampled)`
>`@wordpress/is-shallow-equal (object, unequal) x 4,925,231 ops/sec ±0.28% (91 runs sampled)`
>`@wordpress/is-shallow-equal (array, equal) x 30,432,490 ops/sec ±0.80% (86 runs sampled)`
>`@wordpress/is-shallow-equal (array, same) x 505,206,883 ops/sec ±0.37% (93 runs sampled)`
>`@wordpress/is-shallow-equal (array, unequal) x 33,590,955 ops/sec ±0.96% (86 runs sampled)`
>
>shallow-equal (object, equal) x 4,691,935 ops/sec ±0.66% (90 runs sampled)
>shallow-equal (object, same) x 516,007,655 ops/sec ±0.33% (91 runs sampled)
>shallow-equal (object, unequal) x 4,892,693 ops/sec ±0.36% (92 runs sampled)
>shallow-equal (array, equal) x 62,132,248 ops/sec ±0.35% (90 runs sampled)
>shallow-equal (array, same) x 516,969,309 ops/sec ±0.36% (91 runs sampled)
>shallow-equal (array, unequal) x 34,161,863 ops/sec ±0.87% (87 runs sampled)
>`shallowequal (object, equal) x 3,407,788 ops/sec ±0.46% (93 runs sampled)`
>`shallowequal (object, same) x 494,715,603 ops/sec ±0.42% (91 runs sampled)`
>`shallowequal (object, unequal) x 3,575,393 ops/sec ±0.54% (93 runs sampled)`
>`shallowequal (array, equal) x 1,530,453 ops/sec ±0.32% (92 runs sampled)`
>`shallowequal (array, same) x 489,793,575 ops/sec ±0.60% (90 runs sampled)`
>`shallowequal (array, unequal) x 1,534,574 ops/sec ±0.32% (90 runs sampled)`
>
>is-equal-shallow (object, equal) x 2,892,207 ops/sec ±0.45% (90 runs sampled)
>is-equal-shallow (object, same) x 2,908,156 ops/sec ±0.32% (95 runs sampled)
>is-equal-shallow (object, unequal) x 3,180,995 ops/sec ±0.36% (94 runs sampled)
>is-equal-shallow (array, equal) x 1,105,943 ops/sec ±0.32% (91 runs sampled)
>is-equal-shallow (array, same) x 1,104,462 ops/sec ±0.56% (93 runs sampled)
>is-equal-shallow (array, unequal) x 1,773,097 ops/sec ±0.35% (92 runs sampled)
>`shallow-equal (type specific) (object, equal) x 4,708,043 ops/sec ±0.30% (92 runs sampled)`
>`shallow-equal (type specific) (object, same) x 537,831,873 ops/sec ±0.42% (88 runs sampled)`
>`shallow-equal (type specific) (object, unequal) x 4,859,249 ops/sec ±0.28% (90 runs sampled)`
>`shallow-equal (type specific) (array, equal) x 63,985,372 ops/sec ±0.54% (91 runs sampled)`
>`shallow-equal (type specific) (array, same) x 540,675,335 ops/sec ±0.43% (89 runs sampled)`
>`shallow-equal (type specific) (array, unequal) x 34,613,490 ops/sec ±0.81% (90 runs sampled)`
>
>shallow-equals (object, equal) x 4,400,657 ops/sec ±0.36% (93 runs sampled)
>shallow-equals (object, same) x 4,422,178 ops/sec ±0.27% (92 runs sampled)
>shallow-equals (object, unequal) x 4,705,010 ops/sec ±0.34% (94 runs sampled)
>shallow-equals (array, equal) x 47,976,902 ops/sec ±0.67% (87 runs sampled)
>shallow-equals (array, same) x 66,178,859 ops/sec ±0.62% (85 runs sampled)
>shallow-equals (array, unequal) x 27,154,150 ops/sec ±0.70% (87 runs sampled)
>`is-equal-shallow (object, equal) x 2,798,059 ops/sec ±0.42% (93 runs sampled)`
>`is-equal-shallow (object, same) x 2,844,934 ops/sec ±0.39% (93 runs sampled)`
>`is-equal-shallow (object, unequal) x 3,223,288 ops/sec ±0.57% (92 runs sampled)`
>`is-equal-shallow (array, equal) x 1,060,093 ops/sec ±0.32% (93 runs sampled)`
>`is-equal-shallow (array, same) x 1,058,977 ops/sec ±0.31% (94 runs sampled)`
>`is-equal-shallow (array, unequal) x 1,697,517 ops/sec ±0.28% (91 runs sampled)`
>
>fbjs/lib/shallowEqual (object, equal) x 3,421,137 ops/sec ±0.36% (93 runs sampled)
>fbjs/lib/shallowEqual (object, same) x 503,687,883 ops/sec ±0.40% (91 runs sampled)
>fbjs/lib/shallowEqual (object, unequal) x 3,503,882 ops/sec ±0.68% (93 runs sampled)
>fbjs/lib/shallowEqual (array, equal) x 1,510,797 ops/sec ±0.35% (90 runs sampled)
>fbjs/lib/shallowEqual (array, same) x 245,713,360 ops/sec ±18.06% (48 runs sampled)
>fbjs/lib/shallowEqual (array, unequal) x 1,515,645 ops/sec ±0.33% (92 runs sampled)
>`shallow-equals (object, equal) x 4,457,325 ops/sec ±0.40% (92 runs sampled)`
>`shallow-equals (object, same) x 4,509,250 ops/sec ±0.48% (92 runs sampled)`
>`shallow-equals (object, unequal) x 4,856,327 ops/sec ±0.41% (94 runs sampled)`
>`shallow-equals (array, equal) x 44,915,371 ops/sec ±2.18% (79 runs sampled)`
>`shallow-equals (array, same) x 38,514,418 ops/sec ±1.25% (83 runs sampled)`
>`shallow-equals (array, unequal) x 24,319,893 ops/sec ±0.96% (84 runs sampled)`
>
>`fbjs/lib/shallowEqual (object, equal) x 3,388,692 ops/sec ±0.72% (92 runs sampled)`
>`fbjs/lib/shallowEqual (object, same) x 139,559,732 ops/sec ±4.45% (32 runs sampled)`
>`fbjs/lib/shallowEqual (object, unequal) x 3,480,571 ops/sec ±0.51% (90 runs sampled)`
>`fbjs/lib/shallowEqual (array, equal) x 1,517,044 ops/sec ±0.42% (91 runs sampled)`
>`fbjs/lib/shallowEqual (array, same) x 134,032,009 ops/sec ±2.82% (46 runs sampled)`
>`fbjs/lib/shallowEqual (array, unequal) x 1,532,376 ops/sec ±0.41% (91 runs sampled)`
You can run the benchmarks yourselves by cloning the repository, installing optional dependencies, and running the `benchmark/index.js` script:
You can run the benchmarks yourselves by cloning the repository, installing dependencies, and running the `benchmark/index.js` script:

```
git clone https://github.com/WordPress/packages.git
cd packages/packages/is-shallow-equal
npm install --optional
npm install
node benchmark
```

Expand Down
32 changes: 31 additions & 1 deletion packages/is-shallow-equal/arrays.js
Original file line number Diff line number Diff line change
@@ -1 +1,31 @@
module.exports = require( './' ).isShallowEqualArrays;
'use strict';

/**
* Returns true if the two arrays are shallow equal, or false otherwise.
*
* @param {Array} a First array to compare.
* @param {Array} b Second array to compare.
*
* @return {Boolean} Whether the two arrays are shallow equal.
*/
function isShallowEqualArrays( a, b ) {
var i;

if ( a === b ) {
return true;
}

if ( a.length !== b.length ) {
return false;
}

for ( i = 0; i < a.length; i++ ) {
if ( a[ i ] !== b[ i ] ) {
return false;
}
}

return true;
}

module.exports = isShallowEqualArrays;
5 changes: 4 additions & 1 deletion packages/is-shallow-equal/benchmark/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
'use strict';

const Benchmark = require( 'benchmark' );

const suite = new Benchmark.Suite;
Expand All @@ -12,9 +14,10 @@ const afterArrayEqual = [ 1, 2, 3, 4, 5, 6, 7 ];
const afterArrayUnequal = [ 1, 2, 3, 4, 5, 'Unequal', 7 ];

[
[ '@wordpress/is-shallow-equal (type specific)', require( '../objects' ), require( '../arrays' ) ],
[ '@wordpress/is-shallow-equal', require( '../' ) ],
[ 'shallowequal', require( 'shallowequal' ) ],
[ 'shallow-equal', require( 'shallow-equal/objects' ), require( 'shallow-equal/arrays' ) ],
[ 'shallow-equal (type specific)', require( 'shallow-equal/objects' ), require( 'shallow-equal/arrays' ) ],
[ 'is-equal-shallow', require( 'is-equal-shallow' ) ],
[ 'shallow-equals', require( 'shallow-equals' ) ],
[ 'fbjs/lib/shallowEqual', require( 'fbjs/lib/shallowEqual' ) ],
Expand Down
88 changes: 11 additions & 77 deletions packages/is-shallow-equal/index.js
Original file line number Diff line number Diff line change
@@ -1,69 +1,8 @@
var isArray = Array.isArray,
keys = Object.keys;
'use strict';

/**
* Returns true if the two objects are shallow equal, or false otherwise.
*
* @param {Object} a First object to compare.
* @param {Object} b Second object to compare.
*
* @return {Boolean} Whether the two objects are shallow equal.
*/
function isShallowEqualObjects( a, b ) {
var aKeys, bKeys, i, key;

if ( a === b ) {
return true;
}

aKeys = keys( a );
bKeys = keys( b );

if ( aKeys.length !== bKeys.length ) {
return false;
}

i = 0;

while ( i < aKeys.length ) {
key = aKeys[ i ];
if ( a[ key ] !== b[ key ] ) {
return false;
}

i++;
}

return true;
}

/**
* Returns true if the two arrays are shallow equal, or false otherwise.
*
* @param {Array} a First array to compare.
* @param {Array} b Second array to compare.
*
* @return {Boolean} Whether the two arrays are shallow equal.
*/
function isShallowEqualArrays( a, b ) {
var i;

if ( a === b ) {
return true;
}

if ( a.length !== b.length ) {
return false;
}

for ( i = 0; i < a.length; i++ ) {
if ( a[ i ] !== b[ i ] ) {
return false;
}
}

return true;
}
var isShallowEqualObjects = require( './objects' ),
isShallowEqualArrays = require( './arrays' ),
isArray = Array.isArray;

/**
* Returns true if the two arrays or objects are shallow equal, or false
Expand All @@ -75,20 +14,15 @@ function isShallowEqualArrays( a, b ) {
* @return {Boolean} Whether the two values are shallow equal.
*/
function isShallowEqual( a, b ) {
var aIsArray = isArray( a ),
bIsArray = isArray( b );

if ( aIsArray !== bIsArray ) {
return false;
}

if ( aIsArray ) {
return isShallowEqualArrays( a, b );
if ( a && b ) {
if ( a.constructor === Object && b.constructor === Object ) {
return isShallowEqualObjects( a, b );
} else if ( isArray( a ) && isArray( b ) ) {
return isShallowEqualArrays( a, b );
}
}

return isShallowEqualObjects( a, b );
return a === b;
}

module.exports = isShallowEqual;
module.exports.isShallowEqualObjects = isShallowEqualObjects;
module.exports.isShallowEqualArrays = isShallowEqualArrays;
42 changes: 41 additions & 1 deletion packages/is-shallow-equal/objects.js
Original file line number Diff line number Diff line change
@@ -1 +1,41 @@
module.exports = require( './' ).isShallowEqualObjects;
'use strict';

var keys = Object.keys;

/**
* Returns true if the two objects are shallow equal, or false otherwise.
*
* @param {Object} a First object to compare.
* @param {Object} b Second object to compare.
*
* @return {Boolean} Whether the two objects are shallow equal.
*/
function isShallowEqualObjects( a, b ) {
var aKeys, bKeys, i, key;

if ( a === b ) {
return true;
}

aKeys = keys( a );
bKeys = keys( b );

if ( aKeys.length !== bKeys.length ) {
return false;
}

i = 0;

while ( i < aKeys.length ) {
key = aKeys[ i ];
if ( a[ key ] !== b[ key ] ) {
return false;
}

i++;
}

return true;
};

module.exports = isShallowEqualObjects;
Loading

0 comments on commit e83cca2

Please sign in to comment.