I'm reading the MDN docs on Object.assign()
and came across one phrase that I don't understand:
The Object.assign() method only copies enumerable and own properties from a source object to a target object. It uses [[Get]] on the source and [[Set]] on the target, so it will invoke getters and setters. Therefore it assigns properties versus just copying or defining new properties. This may make it unsuitable for merging new properties into a prototype if the merge sources contain getters. For copying property definitions, including their enumerability, into prototypes Object.getOwnPropertyDescriptor() and Object.defineProperty() should be used instead.
Particularly this line:
This may make it unsuitable for merging new properties into a prototype if the merge sources contain getters.
I'm not exactly sure what a good example is for advocating against using Object.assign
.
assign() The Object. assign() method copies all enumerable own properties from one or more source objects to a target object. It returns the modified target object.
assign() pattern in Node 8.
Object.assign() Method Among the Object constructor methods, there is a method Object. assign() which is used to copy the values and properties from one or more source objects to a target object. It invokes getters and setters since it uses both [[Get]] on the source and [[Set]] on the target.
The difference is that Object. assign changes the object in-place, while the spread operator ( ... ) creates a brand new object, and this will break object reference equality.
A getter is an accessor function for a property that returns the property's value. This is what an object with a getter looks like:
var obj = {
get example() {
console.log("getter was called");
return Math.floor(Math.random() * 100);
}
};
console.log(obj.example);
// Note no () ---------^
Notice that when we read the value of the example
property, the function gets run even though it doesn't look like a function call.
What that part of the MDN docs is saying is that Object.assign
will call that getter, it won't create an equivalent getter on the target object. So:
var obj = {
get example() {
console.log("getter was called");
return Math.floor(Math.random() * 100);
}
};
var obj2 = Object.assign({}, obj); // calls getter
console.log(obj2.example); // just has a simple value
console.log(obj2.example); // same value, no call
console.log(obj2.example); // same value, no call
obj
's example
property has a getter, but obj2
's example
property is just a simple value property. Object.assign
didn't copy the getter, it just grabbed the getter's current value and assigned it ot obj2.example
.
You can copy getters, just not with Object.assign
:
function copyProperties(target, source) {
Object.getOwnPropertyNames(source).forEach(name => {
Object.defineProperty(
target,
name,
Object.getOwnPropertyDescriptor(source, name)
);
});
return target;
}
var obj = {
get example() {
console.log("getter was called");
return Math.floor(Math.random() * 100);
}
};
var obj2 = copyProperties({}, obj); // calls getter
console.log(obj2.example); // calls getter
console.log(obj2.example); // calls getter
console.log(obj2.example); // calls getter
Of course, if the getter isn't designed to be copied between objects (for instance, if example
's getter explicitly used obj
), you may get unexpected results.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With