Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit d8f593c

Browse files
committed
perf(copy): use ES6 Map to track source/destination objects
1 parent e3a378e commit d8f593c

File tree

3 files changed

+84
-9
lines changed

3 files changed

+84
-9
lines changed

src/Angular.js

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -743,6 +743,49 @@ function arrayRemove(array, value) {
743743
return index;
744744
}
745745

746+
747+
function ES6MapShim() {
748+
this._keys = [];
749+
this._values = [];
750+
}
751+
ES6MapShim.prototype = {
752+
get: function(key) {
753+
var idx = this._keys.indexOf(key);
754+
if (idx !== -1) {
755+
return this._values[idx];
756+
}
757+
},
758+
set: function(key, value) {
759+
var idx = this._keys.indexOf(key);
760+
if (idx === -1) {
761+
idx = this._keys.length;
762+
}
763+
this._keys[idx] = key;
764+
this._values[idx] = value;
765+
return this;
766+
}
767+
};
768+
769+
function testES6Map(Map) {
770+
var m, o = {};
771+
return isFunction(Map) && (m = new Map())
772+
773+
// Required functions
774+
&& isFunction(m.get) && isFunction(m.set)
775+
776+
// Number keys, must not call toString
777+
&& m.get(1) === undefined
778+
&& m.set(1, o) === m
779+
&& m.get(1) === o
780+
&& m.get('1') === undefined
781+
782+
// Object keys, must use instance as key and not call toString
783+
&& m.set(o, 2) === m && m.get(o) === 2
784+
&& m.get({}) === undefined;
785+
}
786+
787+
var ES6Map = testES6Map(window.Map) ? window.Map : ES6MapShim;
788+
746789
/**
747790
* @ngdoc function
748791
* @name angular.copy
@@ -809,8 +852,7 @@ function arrayRemove(array, value) {
809852
</example>
810853
*/
811854
function copy(source, destination) {
812-
var stackSource = [];
813-
var stackDest = [];
855+
var stack = new ES6Map();
814856

815857
if (destination) {
816858
if (isTypedArray(destination) || isArrayBuffer(destination)) {
@@ -831,8 +873,7 @@ function copy(source, destination) {
831873
});
832874
}
833875

834-
stackSource.push(source);
835-
stackDest.push(destination);
876+
stack.set(source, destination);
836877
return copyRecurse(source, destination);
837878
}
838879

@@ -876,9 +917,9 @@ function copy(source, destination) {
876917
}
877918

878919
// Already copied values
879-
var index = stackSource.indexOf(source);
880-
if (index !== -1) {
881-
return stackDest[index];
920+
var existingCopy = stack.get(source);
921+
if (existingCopy) {
922+
return existingCopy;
882923
}
883924

884925
if (isWindow(source) || isScope(source)) {
@@ -894,8 +935,7 @@ function copy(source, destination) {
894935
needsRecurse = true;
895936
}
896937

897-
stackSource.push(source);
898-
stackDest.push(destination);
938+
stack.set(source, destination);
899939

900940
return needsRecurse
901941
? copyRecurse(source, destination)

test/.eslintrc.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@
103103
"getBlockNodes": false,
104104
"createMap": false,
105105
"VALIDITY_STATE_PROPERTY": true,
106+
"testES6Map": true,
107+
"ES6MapShim": true,
106108

107109
/* AngularPublic.js */
108110
"version": false,

test/AngularSpec.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,39 @@ describe('angular', function() {
2525
});
2626
});
2727

28+
describe('ES6Map', function() {
29+
it('should test for bad Map objects', function() {
30+
expect(testES6Map()).toBe(false);
31+
expect(testES6Map(null)).toBe(false);
32+
expect(testES6Map(3)).toBe(false);
33+
expect(testES6Map({})).toBe(false);
34+
});
35+
36+
it('should test for bad Map shims', function() {
37+
function NoMethods() {}
38+
39+
function ToStringOnKeys() {
40+
this._vals = {};
41+
}
42+
ToStringOnKeys.prototype = {
43+
get: function(key) {
44+
return this._vals[key];
45+
},
46+
set: function(key, val) {
47+
this._vals[key] = val;
48+
return this;
49+
}
50+
};
51+
52+
expect(testES6Map(NoMethods)).toBe(false);
53+
expect(testES6Map(ToStringOnKeys)).toBe(false);
54+
});
55+
56+
it('should pass the ES6Map test with ES6MapShim', function() {
57+
expect(testES6Map(ES6MapShim)).toBe(true);
58+
});
59+
});
60+
2861
describe('copy', function() {
2962
it('should return same object', function() {
3063
var obj = {};

0 commit comments

Comments
 (0)