Explanation of the usage of Object.assign()
Syntax: Object.assign(target sources) target: target object, sources: source object
Copies the values of all enumerable properties from one or more source objects to the target object. It will return the target object.
const target = { a: 1, b: 2 }; const source = { b: 4, c: 5 }; const returnedTarget = Object.assign(target, source); console.log(target); // Object { a: 1, b: 4, c: 5 } console.log(returnedTarget); // Object { a: 1, b: 4, c: 5 }
Usage example:
- Copy an object
const obj = { a: 1 }; const copy = Object.assign({}, obj); console.log(copy); // { a: 1 }
-
Deep copy problem
For deep copy, you need to use other methods, because Object.assign() copies property values. If the property value of the source object is a reference to an object, then it only points to that reference.
let obj1 = { a: 0 , b: { c: 0}}; let obj2 = Object.assign({}, obj1); console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}} obj1.a = 1; console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 0}} console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}} obj2.a = 2; console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 0}} console.log(JSON.stringify(obj2)); // { a: 2, b: { c: 0}} obj2.b.c = 3; console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 3}} console.log(JSON.stringify(obj2)); // { a: 2, b: { c: 3}} // Deep copy obj1 = { a: 0 , b: { c: 0}}; let obj3 = JSON.parse(JSON.stringify(obj1)); obj1.a = 4; obj1.b.c = 4; console.log(JSON.stringify(obj3)); // { a: 0, b: { c: 0}}
- Merge object
const o1 = { a: 1 }; const o2 = { b: 2 }; const o3 = { c: 3 }; const obj = Object.assign(o1, o2, o3); console.log(obj); // { a: 1, b: 2, c: 3 } console.log(o1); // {a: 1, b: 2, c: 3}, note that the target object itself changes.
- Merge objects with the same properties
const o1 = { a: 1, b: 1, c: 1 }; const o2 = { b: 2, c: 2 }; const o3 = { c: 3 }; const obj = Object.assign({}, o1, o2, o3); console.log(obj); // {a: 1, b: 2, c: 3}, note that the property is overridden by other objects with the same property in subsequent parameters
- Inherited and non enumerated attributes are copied by supplementary courses
const obj = Object.create({foo: 1}, { // foo is an inherited property. bar: { value: 2 // bar is an enumerable property. }, baz: { value: 3, enumerable: true // baz is a self enumerable property. } }); const copy = Object.assign({}, obj); console.log(copy); // { baz: 3 }
- The original type is wrapped as an object
const v1 = "abc"; const v2 = true; const v3 = 10; const v4 = Symbol("foo") const obj = Object.assign({}, v1, null, v2, undefined, v3, v4); // The original type is wrapped and null and undefined are ignored. // Note that only wrapped objects of strings can have their own enumerable properties. console.log(obj); // { "0": "a", "1": "b", "2": "c" }
- Copy properties of Symbol type
const o1 = { a: 1 }; const o2 = { [Symbol('foo')]: 2 }; const obj = Object.assign({}, o1, o2); console.log(obj); // { a : 1, [Symbol("foo")]: 2 } (cf. bug 1207182 on Firefox) Object.getOwnPropertySymbols(obj); // [Symbol(foo)]
- Exceptions break subsequent copies
const target = Object.defineProperty({}, "foo", { value: 1, writable: false }); // The foo property of target is read-only. Object.assign(target, {bar: 2}, {foo2: 3, foo: 3, foo3: 3}, {baz: 4}); // TypeError: "foo" is read-only // Note that this exception occurs when copying the second property of the second source object. console.log(target.bar); // 2. The first source object is copied successfully. console.log(target.foo2); // 3. The first attribute of the second source object is copied successfully. console.log(target.foo); // 1. The read-only attribute cannot be overwritten, so the second attribute copy of the second source object failed. console.log(target.foo3); // undefined. After the exception, the assign method exits. The third attribute will not be copied. console.log(target.baz); // undefined, the third source object will not be copied to.
- Copy accessor
const obj = { foo: 1, get bar() { return 2; } }; let copy = Object.assign({}, obj); console.log(copy); // The value of {foo: 1, bar: 2} copy.bar comes from the return value of the getter function of obj.bar // The following function copies the property descriptors of all its own properties function completeAssign(target, ...sources) { sources.forEach(source => { let descriptors = Object.keys(source).reduce((descriptors, key) => { descriptors[key] = Object.getOwnPropertyDescriptor(source, key); return descriptors; }, {}); // Object.assign also copies enumerable Symbols by default Object.getOwnPropertySymbols(source).forEach(sym => { let descriptor = Object.getOwnPropertyDescriptor(source, sym); if (descriptor.enumerable) { descriptors[sym] = descriptor; } }); Object.defineProperties(target, descriptors); }); return target; } copy = completeAssign({}, obj); console.log(copy); // { foo:1, get bar() { return 2 } }