Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Poor Use Case of Object.assign() - Simple Example

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.

like image 871
qarthandso Avatar asked Aug 19 '17 13:08

qarthandso


People also ask

What is 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.

What can I use instead of object assign?

assign() pattern in Node 8.

How do you assign a value to an object property?

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.

Does object assign modify in place?

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.


1 Answers

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.

like image 123
T.J. Crowder Avatar answered Oct 15 '22 03:10

T.J. Crowder