1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 | 'use strict';
|
11 |
|
12 | var aStackPool = [];
|
13 | var bStackPool = [];
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 | function 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 |
|
34 | function eq(a, b, aStack, bStack) {
|
35 | if (a === b) {
|
36 |
|
37 | return a !== 0 || 1 / a === 1 / b;
|
38 | }
|
39 |
|
40 | if (a == null || b == null) {
|
41 |
|
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 | }
|
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;
|
83 |
|
84 | if (className === '[object Array]') {
|
85 | size = a.length;
|
86 |
|
87 | if (size !== b.length) {
|
88 | return false;
|
89 | }
|
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 |
|
115 |
|
116 |
|
117 |
|
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 |
|
132 | module.exports = areEqual; |
\ | No newline at end of file |