Object.assign()
方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
1
| Object.assign(target, ...sources)
|
参数
返回值
一、描述
如果目标对象中的属性具有相同的键,则属性将被源中的属性覆盖。后来的源的属性将类似地覆盖早先的属性。
Object.assign()
方法只会拷贝源对象自身的并且可枚举的属性到目标对象。该方法使用源对象的[[Get]]
和目标对象的[[Set]]
,所以它会调用相关的getter和setter。因此,它分配属性,而不仅仅是复制或定义新的属性。如果合并源包含getter
,这可能使其不适合将新属性合并到原型中。为了将属性定义(包括其可枚举性)复制到原型,应使用Object.getOwnPropertyDescriptor()
和Object.defineProperty()
。
String
类型和Symbol
类型的属性都会被拷贝。
在出现错误的情况下,例如,如果属性不可写,会引发TypeError
,如果在引发错误之前添加了任何属性,则可以更改target
对象。
注意,Object.assign()
会跳过那些值为null
或undefined
的源对象。
二、示例
1. 复制一个对象
1 2 3
| var obj = { a: 1 }; var copy = Object.assign({}, obj); console.log(copy);
|
2. 只有一个参数
1 2
| var obj = { a: 1 }; Object.assign(obj) === obj;
|
如果该参数不是对象,则会先转换成对象,然后返回
1 2 3 4 5 6 7 8
| Object.assign(true); Object.assign(10); Object.assign('abc');
typeof Object.assign(2);
Object.assign(undefined); Object.assign(null);
|
3. 深拷贝问题
针对深拷贝,需要使用其他方法,因为Object.assign()
拷贝的是属性值。加入源对象的属性值是一个指向对象的引用,它也只拷贝那个引用值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| function test() { 'use strict';
let obj1 = { a: 0, b: { c: 0 } }; let obj2 = Object.assign({}, obj1); console.log(JSON.stringify(obj2));
obj1.a = 1; console.log(JSON.stringify(obj1)); console.log(JSON.stringify(obj2));
obj2.a = 2; console.log(JSON.stringify(obj1)); console.log(JSON.stringify(obj2));
obj2.b.c = 3; console.log(JSON.stringify(obj1)); console.log(JSON.stringify(obj2));
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)); }
test();
|
4. 合并对象
1 2 3 4 5 6 7
| var o1 = { a: 1 }; var o2 = { b: 2 }; var o3 = { c: 3 };
var obj = Object.assign(o1, o2, o3); console.log(obj); console.log(o1);
|
5. 合并具有相同属性的对象
1 2 3 4 5 6
| var o1 = { a: 1, b: 1, c: 1 }; var o2 = { b: 2, c: 2 }; var o3 = { c: 3 };
var obj = Object.assign({}, o1, o2, o3); console.log(obj);
|
属性被后续参数中具有相同属性的其他对象覆盖。
6. 拷贝symbol类型的属性
1 2 3 4 5 6
| var o1 = { a: 1 }; var o2 = { [Symbol('foo')]: 2 };
var obj = Object.assign({}, o1, o2); console.log(obj); Object.getOwnPropertySymbols(obj);
|
7. 继承属性和不可枚举属性
继承属性和不可枚举属性是不能拷贝的
1 2 3 4 5 6 7 8 9 10 11 12
| var obj = Object.create({ foo: 1 }, { bar: { value: 2 }, baz: { value: 3, enumerable: true } });
var copy = Object.assign({}, obj); console.log(copy);
|
8. 原始类型
原始类型会被包装为对象
1 2 3 4 5 6 7 8 9
| var v1 = 'abc'; var v2 = true; var v3 = 10; var v4 = Symbol('foo');
var obj = Object.assign({}, v1, null, v2, undefined, v3, v4);
console.log(obj);
|
9. 异常
异常会打断后续拷贝任务
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| var target = Object.defineProperty({}, 'foo', { value: 1, writable: false });
Object.assign(target, {bar: 2}, {foo2: 2, foo: 3, foo3: 3}, {baz: 4});
console.log(target.bar); console.log(target.foo2); console.log(target.foo); console.log(target.foo3); console.log(target.baz);
|
10. 拷贝访问器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| var obj = { foo: 1, get bar() { return 2; } };
var copy = Object.assign({}, obj);
console.log(copy);
function completeAssign(target, ...sources) { sources.forEach(source => { let descriptors = Object.keys(source).reduce((descrpitors, key) => { descriptors[key] = Object.getOwnPropertyDescriptor(source, key); return descriptors; }, {});
Object.getOwnPropertySymbols(source).forEach(sym => { let descriptor = Object.getOwnPropertyDescriptor(source, sym); if (descriptor.enumerate) { descriptors[sym] = descriptor; } }); Object.defineProperties(target, descriptors); }); return target; }
var copy = completeAssign({}, obj); console.log(copy);
|
参考文献
MDN Object.assign()
阮一峰 ECMAScript 6入门