Object.assign() with accessor descriptor
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 example
1class Cat {
2 constructor(name) {
3 this._name = name;
4 }
5
6 get name() {
7 return this._name;
8 }
9 set name(value) {
10 this._name = value;
11 }
12}
13
14let nyannko = new Cat("nyannko");
15let copy = Object.assign({}, nyannko)
16
17console.log(nyannko.name) // nyannko
18console.log(copy.name) // undefined
The name
property is lost.
To copy accessors, we can use Object.getOwnPropertyDescriptor()
and Object.defineProperty()
as the MDN docs recommend:
1var obj = {
2 foo: 1,
3 get bar() {
4 return 2;
5 }
6};
7
8var copy = Object.assign({}, obj);
9console.log(copy);
10// { foo: 1, bar: 2 }, the value of copy.bar is obj.bar's getter's return value.
11
12// This is an assign function that copies full descriptors
13function completeAssign(target, ...sources) {
14 sources.forEach(source => {
15 let descriptors = Object.keys(source).reduce((descriptors, key) => {
16 descriptors[key] = Object.getOwnPropertyDescriptor(source, key);
17 return descriptors;
18 }, {});
19 // by default, Object.assign copies enumerable Symbols too
20 Object.getOwnPropertySymbols(source).forEach(sym => {
21 let descriptor = Object.getOwnPropertyDescriptor(source, sym);
22 if (descriptor.enumerable) {
23 descriptors[sym] = descriptor;
24 }
25 });
26 Object.defineProperties(target, descriptors);
27 });
28 return target;
29}
30
31var copy = completeAssign({}, obj);
32console.log(copy);
33// { foo:1, get bar() { return 2 } }
The other way is Object.prototype.__proto__
(but not recommended):
1let completeCopy = Object.assign({__proto__: nyannko.__proto__}, nyannko);
2console.log(completeCopy.name); // nyannko
Object.prototype.__proto__
is deprecated so be aware that this may cease to work at any time.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto