36
36
isUndefined: true,
37
37
isDefined: true,
38
38
isObject: true,
39
+ isBlankObject: true,
39
40
isString: true,
40
41
isNumber: true,
41
42
isDate: true,
172
173
splice = [ ] . splice ,
173
174
push = [ ] . push ,
174
175
toString = Object . prototype . toString ,
176
+ getPrototypeOf = Object . getPrototypeOf ,
175
177
ngMinErr = minErr ( 'ng' ) ,
176
178
177
179
/** @name angular */
@@ -461,6 +463,16 @@ function isObject(value) {
461
463
}
462
464
463
465
466
+ /**
467
+ * Determine if a value is an object with a null prototype
468
+ *
469
+ * @returns {boolean } True if `value` is an `Object` with a null prototype
470
+ */
471
+ function isBlankObject ( value ) {
472
+ return value !== null && typeof value === 'object' && ! getPrototypeOf ( value ) ;
473
+ }
474
+
475
+
464
476
/**
465
477
* @ngdoc function
466
478
* @name angular.isString
@@ -742,7 +754,7 @@ function copy(source, destination, stackSource, stackDest) {
742
754
destination = new RegExp ( source . source , source . toString ( ) . match ( / [ ^ \/ ] * $ / ) [ 0 ] ) ;
743
755
destination . lastIndex = source . lastIndex ;
744
756
} else if ( isObject ( source ) ) {
745
- var emptyObject = Object . create ( Object . getPrototypeOf ( source ) ) ;
757
+ var emptyObject = Object . create ( getPrototypeOf ( source ) ) ;
746
758
destination = copy ( source , emptyObject , stackSource , stackDest ) ;
747
759
}
748
760
}
@@ -761,7 +773,7 @@ function copy(source, destination, stackSource, stackDest) {
761
773
stackDest . push ( destination ) ;
762
774
}
763
775
764
- var result ;
776
+ var result , key ;
765
777
if ( isArray ( source ) ) {
766
778
destination . length = 0 ;
767
779
for ( var i = 0 ; i < source . length ; i ++ ) {
@@ -781,21 +793,40 @@ function copy(source, destination, stackSource, stackDest) {
781
793
delete destination [ key ] ;
782
794
} ) ;
783
795
}
784
- for ( var key in source ) {
785
- if ( source . hasOwnProperty ( key ) ) {
786
- result = copy ( source [ key ] , null , stackSource , stackDest ) ;
787
- if ( isObject ( source [ key ] ) ) {
788
- stackSource . push ( source [ key ] ) ;
789
- stackDest . push ( result ) ;
796
+ if ( isBlankObject ( source ) ) {
797
+ // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
798
+ for ( key in source ) {
799
+ putValue ( key , source [ key ] , destination , stackSource , stackDest ) ;
800
+ }
801
+ } else if ( source && typeof source . hasOwnProperty === 'function' ) {
802
+ // Slow path, which must rely on hasOwnProperty
803
+ for ( key in source ) {
804
+ if ( source . hasOwnProperty ( key ) ) {
805
+ putValue ( key , source [ key ] , destination , stackSource , stackDest ) ;
806
+ }
807
+ }
808
+ } else {
809
+ // Slowest path --- hasOwnProperty can't be called as a method
810
+ for ( key in source ) {
811
+ if ( hasOwnProperty . call ( source , key ) ) {
812
+ putValue ( key , source [ key ] , destination , stackSource , stackDest ) ;
790
813
}
791
- destination [ key ] = result ;
792
814
}
793
815
}
794
816
setHashKey ( destination , h ) ;
795
817
}
796
-
797
818
}
798
819
return destination ;
820
+
821
+ function putValue ( key , val , destination , stackSource , stackDest ) {
822
+ // No context allocation, trivial outer scope, easily inlined
823
+ var result = copy ( val , null , stackSource , stackDest ) ;
824
+ if ( isObject ( val ) ) {
825
+ stackSource . push ( val ) ;
826
+ stackDest . push ( result ) ;
827
+ }
828
+ destination [ key ] = result ;
829
+ }
799
830
}
800
831
801
832
/**
0 commit comments