-
-
Notifications
You must be signed in to change notification settings - Fork 32
/
is_equal.ts
135 lines (108 loc) · 2.72 KB
/
is_equal.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// Source: https://github.com/smelukov/nano-equal
export function isEqual(a: any, b: any): boolean {
try {
if (a === b) {
return true;
}
// is nan
if (a !== a && b !== b) {
// eslint-disable-line no-self-compare
return true;
}
const typeA = getType(a);
const typeB = getType(b);
if (typeA !== typeB) {
return false;
}
if (typeA === 'pure-object') {
if (a === b) {
return true;
}
const keysA = Object.keys(a);
const keysBLength = Object.keys(b).length;
if (keysA.length !== keysBLength) {
return false;
}
for (let i = 0, l = keysA.length; i < l; i++) {
const key = keysA[i];
if (!Object.prototype.hasOwnProperty.call(b, keysA[i])) {
return false;
}
const valA = a[key];
const valB = b[key];
// handle recursion
if (valA === a || valB === b || valA === b || valB === a) {
return valA === valB;
}
if (!isEqual(valA, valB)) {
return false;
}
}
return true;
} else if (typeA === 'array') {
if (a.length === b.length) {
for (let j = 0; j < a.length; j++) {
const elA = a[j];
const elB = b[j];
// handle recursion
if (elA === a || elB === b || elA === b || elB === a) {
return elA === elB;
}
if (!isEqual(elA, elB)) {
return false;
}
}
} else {
return false;
}
return true;
} else if (typeA === 'object') {
if (
a.valueOf &&
b.valueOf &&
a.valueOf !== Object.prototype.valueOf() &&
b.valueOf !== Object.prototype.valueOf()
) {
return a.valueOf() === b.valueOf();
}
if (
a.toString &&
a.toString &&
a.toString !== Object.prototype.toString() &&
b.toString !== Object.prototype.toString()
) {
return a.toString() === b.toString();
}
}
} catch (e) {
// We got extremely weird objects, let us skip it and consider them not equal
}
return false;
}
function isArrayLike(a: any): boolean {
if (Array.isArray(a)) {
return true;
}
const len = a.length;
if (typeof len === 'number' && len > -1) {
if (len) {
return 0 in a && len - 1 in a;
}
return true;
}
return false;
}
function getType(a: any): string {
const type = typeof a;
if (type === 'object') {
if (a === null) {
return 'null';
} else if (isArrayLike(a)) {
return 'array';
} else if (a.constructor === Object || Object.getPrototypeOf(a) === null) {
return 'pure-object';
}
return 'object';
}
return type;
}