99 DatePrototypeGetTime,
1010 Error,
1111 NumberPrototypeValueOf,
12+ ObjectGetOwnPropertyDescriptor,
1213 ObjectGetOwnPropertySymbols : getOwnSymbols ,
1314 ObjectGetPrototypeOf,
1415 ObjectIs,
@@ -192,7 +193,10 @@ function innerDeepEqual(val1, val2, mode, memos) {
192193 typeof val1 !== 'object' ||
193194 val1 === null ||
194195 val2 === null ||
195- ( mode === kStrict && ObjectGetPrototypeOf ( val1 ) !== ObjectGetPrototypeOf ( val2 ) ) ) {
196+ ( mode === kStrict &&
197+ ( val1 . constructor !== val2 . constructor ||
198+ ( val1 . constructor === undefined &&
199+ ObjectGetPrototypeOf ( val1 ) !== ObjectGetPrototypeOf ( val2 ) ) ) ) ) {
196200 return false ;
197201 }
198202 } else {
@@ -316,6 +320,10 @@ function innerDeepEqual(val1, val2, mode, memos) {
316320 isNativeError ( val2 ) ||
317321 val2 instanceof Error ) {
318322 return false ;
323+ } else if ( isURL ( val1 ) ) {
324+ if ( ! isURL ( val2 ) || val1 . href !== val2 . href ) {
325+ return false ;
326+ }
319327 } else if ( isKeyObject ( val1 ) ) {
320328 if ( ! isKeyObject ( val2 ) || ! val1 . equals ( val2 ) ) {
321329 return false ;
@@ -332,10 +340,6 @@ function innerDeepEqual(val1, val2, mode, memos) {
332340 }
333341 } else if ( isWeakMap ( val1 ) || isWeakSet ( val1 ) ) {
334342 return false ;
335- } else if ( isURL ( val1 ) ) {
336- if ( ! isURL ( val2 ) || val1 . href !== val2 . href ) {
337- return false ;
338- }
339343 }
340344
341345 return keyCheck ( val1 , val2 , mode , memos , kNoIterator ) ;
@@ -345,6 +349,21 @@ function getEnumerables(val, keys) {
345349 return ArrayPrototypeFilter ( keys , ( key ) => hasEnumerable ( val , key ) ) ;
346350}
347351
352+ function partialSymbolEquiv ( val1 , val2 , keys2 ) {
353+ const symbolKeys = getOwnSymbols ( val2 ) ;
354+ if ( symbolKeys . length !== 0 ) {
355+ for ( const key of symbolKeys ) {
356+ if ( hasEnumerable ( val2 , key ) ) {
357+ if ( ! hasEnumerable ( val1 , key ) ) {
358+ return false ;
359+ }
360+ ArrayPrototypePush ( keys2 , key ) ;
361+ }
362+ }
363+ }
364+ return true ;
365+ }
366+
348367function keyCheck ( val1 , val2 , mode , memos , iterationType , keys2 ) {
349368 // For all remaining Object pairs, including Array, objects and Maps,
350369 // equivalence is determined by having:
@@ -358,31 +377,15 @@ function keyCheck(val1, val2, mode, memos, iterationType, keys2) {
358377 if ( keys2 === undefined ) {
359378 keys2 = ObjectKeys ( val2 ) ;
360379 }
361-
362- // Cheap key test
363- if ( keys2 . length > 0 ) {
364- for ( const key of keys2 ) {
365- if ( ! hasEnumerable ( val1 , key ) ) {
366- return false ;
367- }
368- }
369- }
380+ let keys1 ;
370381
371382 if ( ! isArrayLikeObject ) {
372383 // The pair must have the same number of owned properties.
373384 if ( mode === kPartial ) {
374- const symbolKeys = getOwnSymbols ( val2 ) ;
375- if ( symbolKeys . length !== 0 ) {
376- for ( const key of symbolKeys ) {
377- if ( hasEnumerable ( val2 , key ) ) {
378- if ( ! hasEnumerable ( val1 , key ) ) {
379- return false ;
380- }
381- ArrayPrototypePush ( keys2 , key ) ;
382- }
383- }
385+ if ( ! partialSymbolEquiv ( val1 , val2 , keys2 ) ) {
386+ return false ;
384387 }
385- } else if ( keys2 . length !== ObjectKeys ( val1 ) . length ) {
388+ } else if ( keys2 . length !== ( keys1 = ObjectKeys ( val1 ) ) . length ) {
386389 return false ;
387390 } else if ( mode === kStrict ) {
388391 const symbolKeysA = getOwnSymbols ( val1 ) ;
@@ -431,7 +434,7 @@ function keyCheck(val1, val2, mode, memos, iterationType, keys2) {
431434 d : undefined ,
432435 deep : false ,
433436 } ;
434- return objEquiv ( val1 , val2 , mode , keys2 , memos , iterationType ) ;
437+ return objEquiv ( val1 , val2 , mode , keys1 , keys2 , memos , iterationType ) ;
435438 }
436439
437440 if ( memos . set === undefined ) {
@@ -445,7 +448,7 @@ function keyCheck(val1, val2, mode, memos, iterationType, keys2) {
445448 memos . c = val1 ;
446449 memos . d = val2 ;
447450 memos . deep = true ;
448- const result = objEquiv ( val1 , val2 , mode , keys2 , memos , iterationType ) ;
451+ const result = objEquiv ( val1 , val2 , mode , keys1 , keys2 , memos , iterationType ) ;
449452 memos . deep = false ;
450453 return result ;
451454 }
@@ -465,7 +468,7 @@ function keyCheck(val1, val2, mode, memos, iterationType, keys2) {
465468 return originalSize === set . size ;
466469 }
467470
468- const areEq = objEquiv ( val1 , val2 , mode , keys2 , memos , iterationType ) ;
471+ const areEq = objEquiv ( val1 , val2 , mode , keys1 , keys2 , memos , iterationType ) ;
469472
470473 set . delete ( val1 ) ;
471474 set . delete ( val2 ) ;
@@ -581,16 +584,34 @@ function setEquiv(a, b, mode, memo) {
581584 // This is a lazily initiated Set of entries which have to be compared
582585 // pairwise.
583586 let set = null ;
584- for ( const val of b ) {
587+ const iteratorB = b . values ( ) ;
588+ for ( const val of iteratorB ) {
585589 if ( ! a . has ( val ) ) {
586590 if ( ( typeof val !== 'object' || val === null ) &&
587591 ( mode !== kLoose || ! setMightHaveLoosePrim ( a , b , val ) ) ) {
588592 return false ;
589593 }
590594
591595 if ( set === null ) {
592- if ( a . size === 1 ) {
593- return innerDeepEqual ( a . values ( ) . next ( ) . value , val , mode , memo ) ;
596+ if ( a . size < 3 ) {
597+ const iteratorA = a . values ( ) ;
598+ const firstA = iteratorA . next ( ) . value ;
599+ const first = innerDeepEqual ( firstA , val , mode , memo ) ;
600+ if ( first ) {
601+ if ( b . size === 1 ) { // Partial mode && a.size === 1
602+ return true ;
603+ }
604+ const secondA = iteratorA . next ( ) . value ;
605+ return b . has ( secondA ) || innerDeepEqual ( secondA , iteratorB . next ( ) . value , mode , memo ) ;
606+ }
607+ if ( a . size === 1 ) {
608+ return false ;
609+ }
610+ return innerDeepEqual ( iteratorA . next ( ) . value , val , mode , memo ) && (
611+ b . size === 1 || // Partial mode
612+ b . has ( firstA ) || // Primitive or reference equal
613+ innerDeepEqual ( firstA , iteratorB . next ( ) . value , mode , memo )
614+ ) ;
594615 }
595616 set = new SafeSet ( ) ;
596617 }
@@ -770,11 +791,28 @@ function sparseArrayEquiv(a, b, mode, memos, i) {
770791 return true ;
771792}
772793
773- function objEquiv ( a , b , mode , keys2 , memos , iterationType ) {
794+ function objEquiv ( a , b , mode , keys1 , keys2 , memos , iterationType ) {
774795 // The pair must have equivalent values for every corresponding key.
775796 if ( keys2 . length > 0 ) {
776- for ( const key of keys2 ) {
777- if ( ! innerDeepEqual ( a [ key ] , b [ key ] , mode , memos ) ) {
797+ let i = 0 ;
798+ // Ordered keys
799+ if ( keys1 !== undefined ) {
800+ for ( ; i < keys2 . length ; i ++ ) {
801+ const key = keys2 [ i ] ;
802+ if ( keys1 [ i ] !== key ) {
803+ break ;
804+ }
805+ if ( ! innerDeepEqual ( a [ key ] , b [ key ] , mode , memos ) ) {
806+ return false ;
807+ }
808+ }
809+ }
810+ // Unordered keys
811+ for ( ; i < keys2 . length ; i ++ ) {
812+ const key = keys2 [ i ] ;
813+ const descriptor = ObjectGetOwnPropertyDescriptor ( a , key ) ;
814+ if ( ! descriptor ?. enumerable ||
815+ ! innerDeepEqual ( descriptor . value !== undefined ? descriptor . value : a [ key ] , b [ key ] , mode , memos ) ) {
778816 return false ;
779817 }
780818 }
0 commit comments