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

fix(copy): preserve property descriptors #8034

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
18 changes: 10 additions & 8 deletions src/Angular.js
Original file line number Diff line number Diff line change
Expand Up @@ -807,16 +807,18 @@ function copy(source, destination, stackSource, stackDest) {
forEach(destination, function(value, key) {
delete destination[key];
});
for ( var key in source) {
if(source.hasOwnProperty(key)) {
result = copy(source[key], null, stackSource, stackDest);
if (isObject(source[key])) {
stackSource.push(source[key]);
stackDest.push(result);
forEach (Object.getOwnPropertyNames(source), function(key) {
var propertyDescriptor = Object.getOwnPropertyDescriptor(source, key);
if (propertyDescriptor.hasOwnProperty('value')) {
var sourceValue = propertyDescriptor.value;
propertyDescriptor.value = copy(sourceValue, null, stackSource, stackDest);
if (isObject(sourceValue)) {
stackSource.push(sourceValue);
stackDest.push(propertyDescriptor.value);
}
destination[key] = result;
}
}
Object.defineProperty(destination, key, propertyDescriptor);
});
setHashKey(destination,h);
}

Expand Down
51 changes: 51 additions & 0 deletions test/AngularSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,57 @@ describe('angular', function() {
expect(copy(new Foo()) instanceof Foo).toBe(true);
});

it("should copy own non-enumerable properties", function() {
var obj = {
a: "enumerable"
};
Object.defineProperty(obj, 'b', {
value: "nonEnumerable",
enumerable: false
});
expect(copy(obj).a).toEqual("enumerable");
expect(copy(obj).b).toEqual("nonEnumerable");
});

it("should preserve own property descriptors", function() {
var obj = {};
var aDescriptor = {
value : {foo: 'a'},
writable : true,
enumerable : true,
configurable : true
};
var bDescriptor = {
value : {foo: 'b'},
writable : false,
enumerable : false,
configurable : false
};
var cDescriptor = {
get : function() { return this._c; },
set : function(newValue) { this._c = newValue; },
enumerable : false,
configurable : false
};
Object.defineProperties(obj, {
a: aDescriptor,
b: bDescriptor,
c: cDescriptor
});
obj.c = {foo: 'b'};

var objCopy = copy(obj);
expect(Object.getOwnPropertyDescriptor(objCopy, "a")).toEqual(aDescriptor);
expect(Object.getOwnPropertyDescriptor(objCopy, "b")).toEqual(bDescriptor);
expect(Object.getOwnPropertyDescriptor(objCopy, "c")).toEqual(cDescriptor);
expect(objCopy.a).toEqual(obj.a);
expect(objCopy.a === obj.a).toBe(false);
expect(objCopy.b).toEqual(obj.b);
expect(objCopy.b === obj.b).toBe(false);
expect(objCopy.c).toEqual(obj.c);
expect(objCopy.c === obj.c).toBe(false);
});

it("should copy Date", function() {
var date = new Date(123);
expect(copy(date) instanceof Date).toBeTruthy();
Expand Down