@@ -164,18 +164,6 @@ function isEnumerableOrIdentical(val1, val2, prop, mode, memos, method) {
164164 innerDeepEqual ( val1 [ prop ] , val2 [ prop ] , mode , memos ) ;
165165}
166166
167- // Notes: Type tags are historical [[Class]] properties that can be set by
168- // FunctionTemplate::SetClassName() in C++ or Symbol.toStringTag in JS
169- // and retrieved using Object.prototype.toString.call(obj) in JS
170- // See https://tc39.github.io/ecma262/#sec-object.prototype.tostring
171- // for a list of tags pre-defined in the spec.
172- // There are some unspecified tags in the wild too (e.g. typed array tags).
173- // Since tags can be altered, they only serve fast failures
174- //
175- // For strict comparison, objects should have
176- // a) The same built-in type tag.
177- // b) The same prototypes.
178-
179167function innerDeepEqual ( val1 , val2 , mode , memos ) {
180168 // All identical values are equivalent, as determined by ===.
181169 if ( val1 === val2 ) {
@@ -192,11 +180,7 @@ function innerDeepEqual(val1, val2, mode, memos) {
192180 if ( typeof val2 !== 'object' ||
193181 typeof val1 !== 'object' ||
194182 val1 === null ||
195- val2 === null ||
196- ( mode === kStrict &&
197- ( val1 . constructor !== val2 . constructor ||
198- ( val1 . constructor === undefined &&
199- ObjectGetPrototypeOf ( val1 ) !== ObjectGetPrototypeOf ( val2 ) ) ) ) ) {
183+ val2 === null ) {
200184 return false ;
201185 }
202186 } else {
@@ -210,6 +194,17 @@ function innerDeepEqual(val1, val2, mode, memos) {
210194 return false ;
211195 }
212196 }
197+ return objectComparisonStart ( val1 , val2 , mode , memos ) ;
198+ }
199+
200+ function objectComparisonStart ( val1 , val2 , mode , memos ) {
201+ if ( mode === kStrict &&
202+ ( val1 . constructor !== val2 . constructor ||
203+ ( val1 . constructor === undefined &&
204+ ObjectGetPrototypeOf ( val1 ) !== ObjectGetPrototypeOf ( val2 ) ) ) ) {
205+ return false ;
206+ }
207+
213208 const val1Tag = ObjectPrototypeToString ( val1 ) ;
214209 const val2Tag = ObjectPrototypeToString ( val2 ) ;
215210
@@ -218,7 +213,6 @@ function innerDeepEqual(val1, val2, mode, memos) {
218213 }
219214
220215 if ( ArrayIsArray ( val1 ) ) {
221- // Check for sparse arrays and general fast path
222216 if ( ! ArrayIsArray ( val2 ) ||
223217 ( val1 . length !== val2 . length && ( mode !== kPartial || val1 . length < val2 . length ) ) ) {
224218 return false ;
@@ -473,9 +467,9 @@ function keyCheck(val1, val2, mode, memos, iterationType, keys2) {
473467 return areEq ;
474468}
475469
476- function setHasEqualElement ( set , val1 , mode , memo ) {
470+ function setHasEqualElement ( set , val1 , mode , memo , fn ) {
477471 for ( const val2 of set ) {
478- if ( innerDeepEqual ( val1 , val2 , mode , memo ) ) {
472+ if ( fn ( val1 , val2 , mode , memo ) ) {
479473 // Remove the matching element to make sure we do not check that again.
480474 set . delete ( val2 ) ;
481475 return true ;
@@ -537,7 +531,7 @@ function partialObjectSetEquiv(a, b, mode, set, memo) {
537531 let aPos = 0 ;
538532 for ( const val of a ) {
539533 aPos ++ ;
540- if ( ! b . has ( val ) && setHasEqualElement ( set , val , mode , memo ) && set . size === 0 ) {
534+ if ( ! b . has ( val ) && setHasEqualElement ( set , val , mode , memo , innerDeepEqual ) && set . size === 0 ) {
541535 return true ;
542536 }
543537 if ( a . size - aPos < set . size ) {
@@ -552,7 +546,7 @@ function setObjectEquiv(a, b, mode, set, memo) {
552546 // Fast path for objects only
553547 if ( mode !== kLoose && set . size === a . size ) {
554548 for ( const val of a ) {
555- if ( ! setHasEqualElement ( set , val , mode , memo ) ) {
549+ if ( ! setHasEqualElement ( set , val , mode , memo , objectComparisonStart ) ) {
556550 return false ;
557551 }
558552 }
@@ -562,15 +556,16 @@ function setObjectEquiv(a, b, mode, set, memo) {
562556 return partialObjectSetEquiv ( a , b , mode , set , memo ) ;
563557 }
564558
559+ const fn = mode === kStrict ? objectComparisonStart : innerDeepEqual ;
565560 for ( const val of a ) {
566561 // Primitive values have already been handled above.
567562 if ( typeof val === 'object' ) {
568- if ( ! b . has ( val ) && ! setHasEqualElement ( set , val , mode , memo ) ) {
563+ if ( ! b . has ( val ) && ! setHasEqualElement ( set , val , mode , memo , fn ) ) {
569564 return false ;
570565 }
571566 } else if ( mode === kLoose &&
572567 ! b . has ( val ) &&
573- ! setHasEqualElement ( set , val , mode , memo ) ) {
568+ ! setHasEqualElement ( set , val , mode , memo , innerDeepEqual ) ) {
574569 return false ;
575570 }
576571 }
@@ -626,12 +621,12 @@ function setEquiv(a, b, mode, memo) {
626621 return true ;
627622}
628623
629- function mapHasEqualEntry ( set , map , key1 , item1 , mode , memo ) {
624+ function mapHasEqualEntry ( set , map , key1 , item1 , mode , memo , fn ) {
630625 // To be able to handle cases like:
631626 // Map([[{}, 'a'], [{}, 'b']]) vs Map([[{}, 'b'], [{}, 'a']])
632627 // ... we need to consider *all* matching keys, not just the first we find.
633628 for ( const key2 of set ) {
634- if ( innerDeepEqual ( key1 , key2 , mode , memo ) &&
629+ if ( fn ( key1 , key2 , mode , memo ) &&
635630 innerDeepEqual ( item1 , map . get ( key2 ) , mode , memo ) ) {
636631 set . delete ( key2 ) ;
637632 return true ;
@@ -647,7 +642,7 @@ function partialObjectMapEquiv(a, b, mode, set, memo) {
647642 aPos ++ ;
648643 if ( typeof key1 === 'object' &&
649644 key1 !== null &&
650- mapHasEqualEntry ( set , b , key1 , item1 , mode , memo ) &&
645+ mapHasEqualEntry ( set , b , key1 , item1 , mode , memo , objectComparisonStart ) &&
651646 set . size === 0 ) {
652647 return true ;
653648 }
@@ -663,7 +658,7 @@ function mapObjectEquivalence(a, b, mode, set, memo) {
663658 // Fast path for objects only
664659 if ( mode !== kLoose && set . size === a . size ) {
665660 for ( const { 0 : key1 , 1 : item1 } of a ) {
666- if ( ! mapHasEqualEntry ( set , b , key1 , item1 , mode , memo ) ) {
661+ if ( ! mapHasEqualEntry ( set , b , key1 , item1 , mode , memo , objectComparisonStart ) ) {
667662 return false ;
668663 }
669664 }
@@ -672,16 +667,17 @@ function mapObjectEquivalence(a, b, mode, set, memo) {
672667 if ( mode === kPartial ) {
673668 return partialObjectMapEquiv ( a , b , mode , set , memo ) ;
674669 }
670+ const fn = mode === kStrict ? objectComparisonStart : innerDeepEqual ;
675671 for ( const { 0 : key1 , 1 : item1 } of a ) {
676672 if ( typeof key1 === 'object' && key1 !== null ) {
677- if ( ! mapHasEqualEntry ( set , b , key1 , item1 , mode , memo ) )
673+ if ( ! mapHasEqualEntry ( set , b , key1 , item1 , mode , memo , fn ) )
678674 return false ;
679675 } else if ( set . size === 0 ) {
680676 return true ;
681677 } else if ( mode === kLoose &&
682678 ( ! b . has ( key1 ) ||
683679 ! innerDeepEqual ( item1 , b . get ( key1 ) , mode , memo ) ) &&
684- ! mapHasEqualEntry ( set , b , key1 , item1 , mode , memo ) ) {
680+ ! mapHasEqualEntry ( set , b , key1 , item1 , mode , memo , innerDeepEqual ) ) {
685681 return false ;
686682 }
687683 }
0 commit comments