'use strict'; /** * Copyright (c) 2013-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * * */ var aStackPool = []; var bStackPool = []; /** * Checks if two values are equal. Values may be primitives, arrays, or objects. * Returns true if both arguments have the same keys and values. * * @see http://underscorejs.org * @copyright 2009-2013 Jeremy Ashkenas, DocumentCloud Inc. * @license MIT */ function areEqual(a, b) { var aStack = aStackPool.length ? aStackPool.pop() : []; var bStack = bStackPool.length ? bStackPool.pop() : []; var result = eq(a, b, aStack, bStack); aStack.length = 0; bStack.length = 0; aStackPool.push(aStack); bStackPool.push(bStack); return result; } function eq(a, b, aStack, bStack) { if (a === b) { // Identical objects are equal. `0 === -0`, but they aren't identical. return a !== 0 || 1 / a == 1 / b; } if (a == null || b == null) { // a or b can be `null` or `undefined` return false; } if (typeof a != 'object' || typeof b != 'object') { return false; } var objToStr = Object.prototype.toString; var className = objToStr.call(a); if (className != objToStr.call(b)) { return false; } switch (className) { case '[object String]': return a == String(b); case '[object Number]': return isNaN(a) || isNaN(b) ? false : a == Number(b); case '[object Date]': case '[object Boolean]': return +a == +b; case '[object RegExp]': return a.source == b.source && a.global == b.global && a.multiline == b.multiline && a.ignoreCase == b.ignoreCase; } // Assume equality for cyclic structures. var length = aStack.length; while (length--) { if (aStack[length] == a) { return bStack[length] == b; } } aStack.push(a); bStack.push(b); var size = 0; // Recursively compare objects and arrays. if (className === '[object Array]') { size = a.length; if (size !== b.length) { return false; } // Deep compare the contents, ignoring non-numeric properties. while (size--) { if (!eq(a[size], b[size], aStack, bStack)) { return false; } } } else { if (a.constructor !== b.constructor) { return false; } if (a.hasOwnProperty('valueOf') && b.hasOwnProperty('valueOf')) { return a.valueOf() == b.valueOf(); } var keys = Object.keys(a); if (keys.length != Object.keys(b).length) { return false; } for (var i = 0; i < keys.length; i++) { if (!eq(a[keys[i]], b[keys[i]], aStack, bStack)) { return false; } } } aStack.pop(); bStack.pop(); return true; } module.exports = areEqual;