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

Commit 29c97a6

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

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
@@ -744,6 +744,49 @@ function arrayRemove(array, value) {
744744
return index;
745745
}
746746

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

809851
if (destination) {
810852
if (isTypedArray(destination)) {
@@ -825,8 +867,7 @@ function copy(source, destination) {
825867
});
826868
}
827869

828-
stackSource.push(source);
829-
stackDest.push(destination);
870+
stack.set(source, destination);
830871
return copyRecurse(source, destination);
831872
}
832873

@@ -870,9 +911,9 @@ function copy(source, destination) {
870911
}
871912

872913
// Already copied values
873-
var index = stackSource.indexOf(source);
874-
if (index !== -1) {
875-
return stackDest[index];
914+
var existingCopy = stack.get(source);
915+
if (existingCopy) {
916+
return existingCopy;
876917
}
877918

878919
if (isWindow(source) || isScope(source)) {
@@ -900,8 +941,7 @@ function copy(source, destination) {
900941
needsRecurse = true;
901942
}
902943

903-
stackSource.push(source);
904-
stackDest.push(destination);
944+
stack.set(source, destination);
905945

906946
return needsRecurse
907947
? copyRecurse(source, destination)

test/.jshintrc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@
8585
"getBlockNodes": false,
8686
"createMap": false,
8787
"VALIDITY_STATE_PROPERTY": true,
88+
"testES6Map": true,
89+
"ES6MapShim": true,
8890

8991
/* AngularPublic.js */
9092
"version": false,

test/AngularSpec.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,39 @@ describe('angular', function() {
1616
});
1717
});
1818

19+
describe("ES6Map", function() {
20+
it("should test for bad Map objects", function() {
21+
expect(testES6Map()).toBe(false);
22+
expect(testES6Map(null)).toBe(false);
23+
expect(testES6Map(3)).toBe(false);
24+
expect(testES6Map({})).toBe(false);
25+
});
26+
27+
it("should test for bad Map shims", function() {
28+
function NoMethods() {}
29+
30+
function ToStringOnKeys() {
31+
this._vals = {};
32+
}
33+
ToStringOnKeys.prototype = {
34+
get: function(key) {
35+
return this._vals[key];
36+
},
37+
set: function(key, val) {
38+
this._vals[key] = val;
39+
return this;
40+
}
41+
};
42+
43+
expect(testES6Map(NoMethods)).toBe(false);
44+
expect(testES6Map(ToStringOnKeys)).toBe(false);
45+
});
46+
47+
it("should pass the ES6Map test with ES6MapShim", function() {
48+
expect(testES6Map(ES6MapShim)).toBe(true);
49+
});
50+
});
51+
1952
describe("copy", function() {
2053
it("should return same object", function() {
2154
var obj = {};

0 commit comments

Comments
 (0)