@@ -4,6 +4,7 @@ const { compare } = process.binding('buffer');
4
4
const { isArrayBufferView } = require ( 'internal/util/types' ) ;
5
5
const { internalBinding } = require ( 'internal/bootstrap/loaders' ) ;
6
6
const { isDate, isMap, isRegExp, isSet } = internalBinding ( 'types' ) ;
7
+ const { getOwnNonIndexProperties } = process . binding ( 'util' ) ;
7
8
8
9
const ReflectApply = Reflect . apply ;
9
10
@@ -106,24 +107,11 @@ function strictDeepEqual(val1, val2, memos) {
106
107
if ( val1 . length !== val2 . length ) {
107
108
return false ;
108
109
}
109
- const keys = objectKeys ( val1 ) ;
110
- if ( keys . length !== objectKeys ( val2 ) . length ) {
110
+ const keys1 = getOwnNonIndexProperties ( val1 ) ;
111
+ if ( keys1 . length !== getOwnNonIndexProperties ( val2 ) . length ) {
111
112
return false ;
112
113
}
113
- // Fast path for non sparse arrays (no key comparison for indices
114
- // properties).
115
- // See https://tc39.github.io/ecma262/#sec-ordinaryownpropertykeys
116
- if ( val1 . length === keys . length ) {
117
- if ( keys . length === 0 || keys [ val1 . length - 1 ] === `${ val1 . length - 1 } ` ) {
118
- return keyCheck ( val1 , val2 , kStrict , memos , kIsArray , [ ] ) ;
119
- }
120
- } else if ( keys . length > val1 . length &&
121
- keys [ val1 . length - 1 ] === `${ val1 . length - 1 } ` ) {
122
- const minimalKeys = keys . slice ( val1 . length ) ;
123
- return keyCheck ( val1 , val2 , kStrict , memos , kIsArray , minimalKeys ) ;
124
- }
125
- // Only set this to kIsArray in case the array is not sparse!
126
- return keyCheck ( val1 , val2 , kStrict , memos , kNoIterator , keys ) ;
114
+ return keyCheck ( val1 , val2 , kStrict , memos , kIsArray , keys1 ) ;
127
115
}
128
116
if ( val1Tag === '[object Object]' ) {
129
117
return keyCheck ( val1 , val2 , kStrict , memos , kNoIterator ) ;
@@ -148,18 +136,14 @@ function strictDeepEqual(val1, val2, memos) {
148
136
if ( ! areSimilarTypedArrays ( val1 , val2 ) ) {
149
137
return false ;
150
138
}
151
- // Buffer.compare returns true, so val1.length === val2.length
152
- // if they both only contain numeric keys, we don't need to exam further.
153
- const keys = objectKeys ( val1 ) ;
154
- if ( keys . length !== objectKeys ( val2 ) . length ) {
139
+ // Buffer.compare returns true, so val1.length === val2.length. If they both
140
+ // only contain numeric keys, we don't need to exam further than checking
141
+ // the symbols.
142
+ const keys1 = getOwnNonIndexProperties ( val1 ) ;
143
+ if ( keys1 . length !== getOwnNonIndexProperties ( val2 ) . length ) {
155
144
return false ;
156
145
}
157
- if ( keys . length === val1 . length ) {
158
- return keyCheck ( val1 , val2 , kStrict , memos , kNoIterator , [ ] ) ;
159
- }
160
- // Only compare the special keys.
161
- const minimalKeys = keys . slice ( val1 . length ) ;
162
- return keyCheck ( val1 , val2 , kStrict , memos , kNoIterator , minimalKeys ) ;
146
+ return keyCheck ( val1 , val2 , kStrict , memos , kNoIterator , keys1 ) ;
163
147
} else if ( isSet ( val1 ) ) {
164
148
if ( ! isSet ( val2 ) || val1 . size !== val2 . size ) {
165
149
return false ;
@@ -173,21 +157,10 @@ function strictDeepEqual(val1, val2, memos) {
173
157
// TODO: Make the valueOf checks safe.
174
158
} else if ( typeof val1 . valueOf === 'function' ) {
175
159
const val1Value = val1 . valueOf ( ) ;
176
- if ( val1Value !== val1 ) {
177
- if ( typeof val2 . valueOf !== 'function' ) {
178
- return false ;
179
- }
180
- if ( ! innerDeepEqual ( val1Value , val2 . valueOf ( ) , true ) )
181
- return false ;
182
- // Fast path for boxed primitive strings.
183
- if ( typeof val1Value === 'string' ) {
184
- const keys = objectKeys ( val1 ) ;
185
- if ( keys . length !== objectKeys ( val2 ) . length ) {
186
- return false ;
187
- }
188
- const minimalKeys = keys . slice ( val1 . length ) ;
189
- return keyCheck ( val1 , val2 , kStrict , memos , kNoIterator , minimalKeys ) ;
190
- }
160
+ if ( val1Value !== val1 &&
161
+ ( typeof val2 . valueOf !== 'function' ||
162
+ ! innerDeepEqual ( val1Value , val2 . valueOf ( ) , kStrict ) ) ) {
163
+ return false ;
191
164
}
192
165
}
193
166
return keyCheck ( val1 , val2 , kStrict , memos , kNoIterator ) ;
@@ -277,7 +250,7 @@ function keyCheck(val1, val2, strict, memos, iterationType, aKeys) {
277
250
}
278
251
}
279
252
280
- if ( strict ) {
253
+ if ( strict && arguments . length === 5 ) {
281
254
const symbolKeysA = getOwnPropertySymbols ( val1 ) ;
282
255
if ( symbolKeysA . length !== 0 ) {
283
256
let count = 0 ;
@@ -310,7 +283,7 @@ function keyCheck(val1, val2, strict, memos, iterationType, aKeys) {
310
283
if ( aKeys . length === 0 &&
311
284
( iterationType === kNoIterator ||
312
285
iterationType === kIsArray && val1 . length === 0 ||
313
- val1 . size === 0 ) ) {
286
+ val1 . size === 0 ) ) {
314
287
return true ;
315
288
}
316
289
@@ -578,8 +551,28 @@ function objEquiv(a, b, strict, keys, memos, iterationType) {
578
551
}
579
552
} else if ( iterationType === kIsArray ) {
580
553
for ( ; i < a . length ; i ++ ) {
581
- if ( ! innerDeepEqual ( a [ i ] , b [ i ] , strict , memos ) ) {
554
+ if ( hasOwnProperty ( a , i ) ) {
555
+ if ( ! hasOwnProperty ( b , i ) ||
556
+ ! innerDeepEqual ( a [ i ] , b [ i ] , strict , memos ) ) {
557
+ return false ;
558
+ }
559
+ } else if ( hasOwnProperty ( b , i ) ) {
582
560
return false ;
561
+ } else {
562
+ // Array is sparse.
563
+ const keysA = objectKeys ( a ) ;
564
+ i ++ ;
565
+ for ( ; i < keysA . length ; i ++ ) {
566
+ const key = keysA [ i ] ;
567
+ if ( ! hasOwnProperty ( b , key ) ||
568
+ ! innerDeepEqual ( a [ key ] , b [ i ] , strict , memos ) ) {
569
+ return false ;
570
+ }
571
+ }
572
+ if ( keysA . length !== objectKeys ( b ) . length ) {
573
+ return false ;
574
+ }
575
+ return true ;
583
576
}
584
577
}
585
578
}
0 commit comments