7
7
isDate,
8
8
isMap,
9
9
isRegExp,
10
- isSet
10
+ isSet,
11
+ isNativeError,
12
+ isBoxedPrimitive,
13
+ isNumberObject,
14
+ isStringObject,
15
+ isBooleanObject,
16
+ isBigIntObject,
17
+ isSymbolObject
11
18
} = internalBinding ( 'types' ) ;
12
19
const {
13
20
getOwnNonIndexProperties,
@@ -33,6 +40,13 @@ const kIsMap = 3;
33
40
const objectToString = uncurryThis ( Object . prototype . toString ) ;
34
41
const hasOwnProperty = uncurryThis ( Object . prototype . hasOwnProperty ) ;
35
42
const propertyIsEnumerable = uncurryThis ( Object . prototype . propertyIsEnumerable ) ;
43
+ const dateGetTime = uncurryThis ( Date . prototype . getTime ) ;
44
+
45
+ const bigIntValueOf = uncurryThis ( BigInt . prototype . valueOf ) ;
46
+ const booleanValueOf = uncurryThis ( Boolean . prototype . valueOf ) ;
47
+ const numberValueOf = uncurryThis ( Number . prototype . valueOf ) ;
48
+ const symbolValueOf = uncurryThis ( Symbol . prototype . valueOf ) ;
49
+ const stringValueOf = uncurryThis ( String . prototype . valueOf ) ;
36
50
37
51
const objectKeys = Object . keys ;
38
52
const getPrototypeOf = Object . getPrototypeOf ;
@@ -82,6 +96,24 @@ function isObjectOrArrayTag(tag) {
82
96
return tag === '[object Array]' || tag === '[object Object]' ;
83
97
}
84
98
99
+ function isEqualBoxedPrimitive ( val1 , val2 ) {
100
+ if ( isNumberObject ( val1 ) ) {
101
+ return isNumberObject ( val2 ) &&
102
+ objectIs ( numberValueOf ( val1 ) , numberValueOf ( val2 ) ) ;
103
+ }
104
+ if ( isStringObject ( val1 ) ) {
105
+ return isStringObject ( val2 ) && stringValueOf ( val1 ) === stringValueOf ( val2 ) ;
106
+ }
107
+ if ( isBooleanObject ( val1 ) ) {
108
+ return isBooleanObject ( val2 ) &&
109
+ booleanValueOf ( val1 ) === booleanValueOf ( val2 ) ;
110
+ }
111
+ if ( isBigIntObject ( val1 ) ) {
112
+ return isBigIntObject ( val2 ) && bigIntValueOf ( val1 ) === bigIntValueOf ( val2 ) ;
113
+ }
114
+ return isSymbolObject ( val2 ) && symbolValueOf ( val1 ) === symbolValueOf ( val2 ) ;
115
+ }
116
+
85
117
// Notes: Type tags are historical [[Class]] properties that can be set by
86
118
// FunctionTemplate::SetClassName() in C++ or Symbol.toStringTag in JS
87
119
// and retrieved using Object.prototype.toString.call(obj) in JS
@@ -117,7 +149,7 @@ function strictDeepEqual(val1, val2, memos) {
117
149
if ( getPrototypeOf ( val1 ) !== getPrototypeOf ( val2 ) ) {
118
150
return false ;
119
151
}
120
- if ( val1Tag === '[object Array]' ) {
152
+ if ( Array . isArray ( val1 ) ) {
121
153
// Check for sparse arrays and general fast path
122
154
if ( val1 . length !== val2 . length ) {
123
155
return false ;
@@ -133,15 +165,14 @@ function strictDeepEqual(val1, val2, memos) {
133
165
return keyCheck ( val1 , val2 , kStrict , memos , kNoIterator ) ;
134
166
}
135
167
if ( isDate ( val1 ) ) {
136
- // TODO: Make these safe.
137
- if ( val1 . getTime ( ) !== val2 . getTime ( ) ) {
168
+ if ( dateGetTime ( val1 ) !== dateGetTime ( val2 ) ) {
138
169
return false ;
139
170
}
140
171
} else if ( isRegExp ( val1 ) ) {
141
172
if ( ! areSimilarRegExps ( val1 , val2 ) ) {
142
173
return false ;
143
174
}
144
- } else if ( val1Tag === '[object Error]' ) {
175
+ } else if ( isNativeError ( val1 ) || val1 instanceof Error ) {
145
176
// Do not compare the stack as it might differ even though the error itself
146
177
// is otherwise identical. The non-enumerable name should be identical as
147
178
// the prototype is also identical. Otherwise this is caught later on.
@@ -175,14 +206,8 @@ function strictDeepEqual(val1, val2, memos) {
175
206
if ( ! areEqualArrayBuffers ( val1 , val2 ) ) {
176
207
return false ;
177
208
}
178
- // TODO: Make the valueOf checks safe.
179
- } else if ( typeof val1 . valueOf === 'function' ) {
180
- const val1Value = val1 . valueOf ( ) ;
181
- if ( val1Value !== val1 &&
182
- ( typeof val2 . valueOf !== 'function' ||
183
- ! innerDeepEqual ( val1Value , val2 . valueOf ( ) , kStrict ) ) ) {
184
- return false ;
185
- }
209
+ } else if ( isBoxedPrimitive ( val1 ) && ! isEqualBoxedPrimitive ( val1 , val2 ) ) {
210
+ return false ;
186
211
}
187
212
return keyCheck ( val1 , val2 , kStrict , memos , kNoIterator ) ;
188
213
}
0 commit comments