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

fix(angular.copy): copy own non-enumerable properties #15693

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/Angular.js
Original file line number Diff line number Diff line change
Expand Up @@ -941,6 +941,17 @@ function copy(source, destination, maxDepth) {
for (key in source) {
destination[key] = copyElement(source[key], maxDepth);
}
// don't use Object.getOwnPropertyNames with RegExp to avoid copying RegExp lastIndex property
} else if (isObject(source) && typeof Object.getOwnPropertyNames === 'function' && !isRegExp(source)) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if it is reasonable to do isRegExp check here as I assume it can affect performance.

Not doing this check leads to copying own non-enumerable lastIndex property of RegExp object to destination.

Object.getOwnPropertyNames(source).forEach(function(key) {
var elementCopy = copyElement(source[key], maxDepth);

if (source.propertyIsEnumerable(key)) {
destination[key] = elementCopy;
} else {
Object.defineProperty(destination, key, {value: elementCopy});
}
});
} else if (source && typeof source.hasOwnProperty === 'function') {
// Slow path, which must rely on hasOwnProperty
for (key in source) {
Expand Down
11 changes: 11 additions & 0 deletions test/AngularSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,17 @@ describe('angular', function() {
expect(dest).toEqual({a1: 1, b1: {b2: {b3: 1}}, c1: [1, {c2: 1}], d1: {d2: 1}});
});

it('should copy own non-enumerable properties keeping them non-enumerable', function() {
var getter = function() { return Math.random(); };
var source = {};
var dest;

Object.defineProperty(source, 'getter', {value: getter});
dest = copy(source);
expect(dest.getter).toBe(getter);
expect(dest.propertyIsEnumerable('getter')).toBe(false);
});

they('should copy source and ignore max depth when maxDepth = $prop',
[NaN, null, undefined, true, false, -1, 0], function(maxDepth) {
var source = {a1: 1, b1: {b2: {b3: 1}}, c1: [1, {c2: 1}], d1: {d2: 1}};
Expand Down