Created
February 29, 2016 16:41
-
-
Save DmitryDorofeev/d8345aba7c8ccd45e782 to your computer and use it in GitHub Desktop.
underscore deepequal (http://jsbench.github.io/#d8345aba7c8ccd45e782) #jsbench #jsperf
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"/> | |
<title>underscore deepequal</title> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/benchmark/1.0.0/benchmark.min.js"></script> | |
<script src="./suite.js"></script> | |
</head> | |
<body> | |
<h1>Open the console to view the results</h1> | |
<h2><code>cmd + alt + j</code> or <code>ctrl + alt + j</code></h2> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
(function (factory) { | |
if (typeof Benchmark !== "undefined") { | |
factory(Benchmark); | |
} else { | |
factory(require("benchmark")); | |
} | |
})(function (Benchmark) { | |
var suite = new Benchmark.Suite; | |
Benchmark.prototype.setup = function () { | |
var has = function(obj, key) { | |
return obj != null && hasOwnProperty.call(obj, key); | |
} | |
var isObject = function(obj) { | |
var type = typeof obj; | |
return type === 'function' || type === 'object' && !!obj; | |
} | |
var isFunction = function(obj) { | |
return typeof obj == 'function' || false; | |
} | |
var keyss = function(obj) { | |
if (!isObject(obj)) return []; | |
var keys = []; | |
for (var key in obj) if (has(obj, key)) keys.push(key); | |
return keys; | |
}; | |
var deepEq = function(a, b, aStack, bStack) { | |
var className = Object.prototype.toString.call(a); | |
if (className !== Object.prototype.toString.call(b)) return false; | |
switch (className) { | |
// Strings, numbers, regular expressions, dates, and booleans are compared by value. | |
case '[object RegExp]': | |
// RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i') | |
case '[object String]': | |
// Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is | |
// equivalent to `new String("5")`. | |
return '' + a === '' + b; | |
case '[object Number]': | |
// `NaN`s are equivalent, but non-reflexive. | |
// Object(NaN) is equivalent to NaN. | |
if (+a !== +a) return +b !== +b; | |
// An `egal` comparison is performed for other numeric values. | |
return +a === 0 ? 1 / +a === 1 / b : +a === +b; | |
case '[object Date]': | |
case '[object Boolean]': | |
// Coerce dates and booleans to numeric primitive values. Dates are compared by their | |
// millisecond representations. Note that invalid dates with millisecond representations | |
// of `NaN` are not equivalent. | |
return +a === +b; | |
case '[object Symbol]': | |
return Symbol.prototype.valueOf.call(a) === Symbol.prototype.valueOf.call(b); | |
} | |
var areArrays = className === '[object Array]'; | |
if (!areArrays) { | |
if (typeof a != 'object' || typeof b != 'object') return false; | |
// Objects with different constructors are not equivalent, but `Object`s or `Array`s | |
// from different frames are. | |
var aCtor = a.constructor, bCtor = b.constructor; | |
if (aCtor !== bCtor && !(isFunction(aCtor) && aCtor instanceof aCtor && | |
isFunction(bCtor) && bCtor instanceof bCtor) | |
&& ('constructor' in a && 'constructor' in b)) { | |
return false; | |
} | |
} | |
// Assume equality for cyclic structures. The algorithm for detecting cyclic | |
// structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. | |
// Initializing stack of traversed objects. | |
// It's done here since we only need them for objects and arrays comparison. | |
aStack = aStack || []; | |
bStack = bStack || []; | |
var length = aStack.length; | |
while (length--) { | |
// Linear search. Performance is inversely proportional to the number of | |
// unique nested structures. | |
if (aStack[length] === a) return bStack[length] === b; | |
} | |
// Add the first object to the stack of traversed objects. | |
aStack.push(a); | |
bStack.push(b); | |
// Recursively compare objects and arrays. | |
if (areArrays) { | |
// Compare array lengths to determine if a deep comparison is necessary. | |
length = a.length; | |
if (length !== b.length) return false; | |
// Deep compare the contents, ignoring non-numeric properties. | |
while (length--) { | |
if (!deepEq(a[length], b[length], aStack, bStack)) return false; | |
} | |
} else { | |
// Deep compare objects. | |
var keys = keyss(a), key; | |
length = keys.length; | |
// Ensure that both objects contain the same number of properties before comparing deep equality. | |
if (keyss(b).length !== length) return false; | |
while (length--) { | |
// Deep compare each member | |
key = keys[length]; | |
if (!(has(b, key) && deepEq(a[key], b[key], aStack, bStack))) return false; | |
} | |
} | |
// Remove the first object from the stack of traversed objects. | |
aStack.pop(); | |
bStack.pop(); | |
return true; | |
} | |
}; | |
suite.add("var a = { hello: 'hello', b: { a: [ '77', 89, {} ] }, c: 'ga', lol: NaN };", function () { | |
var a = { hello: 'hello', b: { a: [ '77', 89, {} ] }, c: 'ga', lol: NaN }; | |
var b = { hello: 'hello', b: { a: [ '77', 89, {} ] }, c: 'ga', lol: NaN }; | |
deepEq(a, b) | |
}); | |
suite.add("var a = { hello: 'hello', b: { a: [ '77', 89, {} ] }, c: 'ga', lol: NaN };", function () { | |
var a = { hello: 'hello', b: { a: [ '77', 89, {} ] }, c: 'ga', lol: NaN }; | |
var b = { hello: 'hello', b: { a: [ '77', 89, {} ] }, c: 'ga', lol: NaN }; | |
JSON.stringify(a) | |
JSON.stringify(b) | |
a === b | |
}); | |
suite.on("cycle", function (evt) { | |
console.log(" - " + evt.target); | |
}); | |
suite.on("complete", function (evt) { | |
console.log(new Array(30).join("-")); | |
var results = evt.currentTarget.sort(function (a, b) { | |
return b.hz - a.hz; | |
}); | |
results.forEach(function (item) { | |
console.log((idx + 1) + ". " + item); | |
}); | |
}); | |
console.log("underscore deepequal"); | |
console.log(new Array(30).join("-")); | |
suite.run(); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment