UNPKG

3.18 kBJavaScriptView Raw
1/**
2 * Copyright (c) Facebook, Inc. and its affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 *
8 * @format
9 */
10'use strict';
11
12var aStackPool = [];
13var bStackPool = [];
14/**
15 * Checks if two values are equal. Values may be primitives, arrays, or objects.
16 * Returns true if both arguments have the same keys and values.
17 *
18 * @see http://underscorejs.org
19 * @copyright 2009-2013 Jeremy Ashkenas, DocumentCloud Inc.
20 * @license MIT
21 */
22
23function areEqual(a, b) {
24 var aStack = aStackPool.length ? aStackPool.pop() : [];
25 var bStack = bStackPool.length ? bStackPool.pop() : [];
26 var result = eq(a, b, aStack, bStack);
27 aStack.length = 0;
28 bStack.length = 0;
29 aStackPool.push(aStack);
30 bStackPool.push(bStack);
31 return result;
32}
33
34function eq(a, b, aStack, bStack) {
35 if (a === b) {
36 // Identical objects are equal. `0 === -0`, but they aren't identical.
37 return a !== 0 || 1 / a === 1 / b;
38 }
39
40 if (a == null || b == null) {
41 // a or b can be `null` or `undefined`
42 return false;
43 }
44
45 if (typeof a !== 'object' || typeof b !== 'object') {
46 return false;
47 }
48
49 var objToStr = Object.prototype.toString;
50 var className = objToStr.call(a);
51
52 if (className !== objToStr.call(b)) {
53 return false;
54 }
55
56 switch (className) {
57 case '[object String]':
58 return a === String(b);
59
60 case '[object Number]':
61 return isNaN(a) || isNaN(b) ? false : a === Number(b);
62
63 case '[object Date]':
64 case '[object Boolean]':
65 return +a === +b;
66
67 case '[object RegExp]':
68 return a.source === b.source && a.global === b.global && a.multiline === b.multiline && a.ignoreCase === b.ignoreCase;
69 } // Assume equality for cyclic structures.
70
71
72 var length = aStack.length;
73
74 while (length--) {
75 if (aStack[length] === a) {
76 return bStack[length] === b;
77 }
78 }
79
80 aStack.push(a);
81 bStack.push(b);
82 var size = 0; // Recursively compare objects and arrays.
83
84 if (className === '[object Array]') {
85 size = a.length;
86
87 if (size !== b.length) {
88 return false;
89 } // Deep compare the contents, ignoring non-numeric properties.
90
91
92 while (size--) {
93 if (!eq(a[size], b[size], aStack, bStack)) {
94 return false;
95 }
96 }
97 } else {
98 if (a.constructor !== b.constructor) {
99 return false;
100 }
101
102 if (a.hasOwnProperty('valueOf') && b.hasOwnProperty('valueOf')) {
103 return a.valueOf() === b.valueOf();
104 }
105
106 var keys = Object.keys(a);
107
108 if (keys.length !== Object.keys(b).length) {
109 return false;
110 }
111
112 for (var i = 0; i < keys.length; i++) {
113 if (keys[i] === '_owner') {
114 // HACK: Comparing deeply nested React trees is slow since you end up
115 // comparing the entire tree (all ancestors and all children) and
116 // likely not what you want if you're comparing two elements with
117 // areEqual. We bail out here for now.
118 continue;
119 }
120
121 if (!b.hasOwnProperty(keys[i]) || !eq(a[keys[i]], b[keys[i]], aStack, bStack)) {
122 return false;
123 }
124 }
125 }
126
127 aStack.pop();
128 bStack.pop();
129 return true;
130}
131
132module.exports = areEqual;
\No newline at end of file