Skip to content

Instantly share code, notes, and snippets.

@DmitryDorofeev
Created February 29, 2016 16:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DmitryDorofeev/d8345aba7c8ccd45e782 to your computer and use it in GitHub Desktop.
Save DmitryDorofeev/d8345aba7c8ccd45e782 to your computer and use it in GitHub Desktop.
underscore deepequal (http://jsbench.github.io/#d8345aba7c8ccd45e782) #jsbench #jsperf
<!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>
"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