1、Object.assign()是什么?
Object.assign()
方法用于将所有可枚举属性的值从一个或多个源对象分配到目标对象。它将返回目标对象。
tips:在JavaScript中枚举属性简单来说就是指对象中的属性是否可以被遍历出来,是属性的enumerable值决定的
2、基本用法
const target = { a: 1, b: 2 }; const source = { b: 3, c: 4 }; const source2 = { c: 5, d: 6 }; const currentTarget = Object.assign(target, source, source2); console.log(currentTarget); // currentTarget: {a: 1, b: 3, c: 5, d: 6}
Object.assign方法的第一个参数是目标对象,后边的其他参数都是源对象;
tips:
1、如果目标对象中的属性具有相同的键,则属性将被源对象中的属性覆盖。后面的源对象的属性将类似地覆盖前面的源对象的属性。
2、Object.assign 方法只会拷贝源对象自身的并且可枚举的属性到目标对象。
3、注意目标自身也会改变
如果只有一个参数,Object.assign会直接返回该参数
const target = { a: 1, b: 2 }; const currentTarget = Object.assign(target); console.log(currentTarget); //{a: 1, b: 2}
该参数不是对象会先转为对象,然后return;(undefined || unll 出现在target(源对象)位置无法转换为对象会报错)
const currentTarget = Object.assign(10); console.log(currentTarget); //Number {10}
注意,Object.assign
不会在那些source
对象值为 null
或 undefined
的时候抛出错误。
其他类型的值(即数值、字符串和布尔值)不在首参数,也不会报错。但是,除了字符串会以数组形式,拷贝入目标对象,其他值都不会产生效果。
const source1 = "aaa"; const source2 = false; const source3 = 666; const currentTarget = Object.assign({}, source1, source2, source3); console.log(currentTarget); //{0: "a", 1: "a", 2: "a"}
Symbol
类型的属性也会被拷贝。
const target = { a: "111" }; const source1 = { [Symbol("6")]: 666 }; const currentTarget = Object.assign(target, source1); console.log(currentTarget); //{a: "111", Symbol(6): 666}
继承属性和不可枚举属性是不能拷贝的
const obj = Object.create({foo: 1}, { // foo 是个继承属性。 bar: { value: 2 // bar 是个不可枚举属性。 }, baz: { value: 3, enumerable: true // baz 是个自身可枚举属性。 } }); const currentTarget= Object.assign({}, obj); console.log(currentTarget); // { baz: 3 }
出现异常会打断后续的copy任务
const target = Object.defineProperty({}, "foo", { value: 1, writable: false }); // target 的 foo 属性是个只读属性。 Object.assign(target, {bar: 2}, {foo2: 3, foo: 3, foo3: 3}, {baz: 4}); // TypeError: "foo" is read-only // 注意这个异常是在拷贝第二个源对象的第二个属性时发生的。 console.log(target.bar); // 2,说明第一个源对象拷贝成功了。 console.log(target.foo2); // 3,说明第二个源对象的第一个属性也拷贝成功了。 console.log(target.foo); // 1,只读属性不能被覆盖,所以第二个源对象的第二个属性拷贝失败了。 console.log(target.foo3); // undefined,异常之后 assign 方法就退出了,第三个属性是不会被拷贝到的。 console.log(target.baz); // undefined,第三个源对象更是不会被拷贝到的。
深拷贝问题
针对深拷贝,需要使用其他办法,因为 Object.assign()
拷贝的是(可枚举)属性值。
假如源值是一个对象的引用,它仅仅会复制其引用值。
const log = console.log; function test() { let obj1 = { a: 0 , b: { c: 0}}; let obj2 = Object.assign({}, obj1); log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}} obj1.a = 1; log(JSON.stringify(obj1)); // { a: 1, b: { c: 0}} log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}} obj2.a = 2; log(JSON.stringify(obj1)); // { a: 1, b: { c: 0}} log(JSON.stringify(obj2)); // { a: 2, b: { c: 0}} obj2.b.c = 3; log(JSON.stringify(obj1)); // { a: 1, b: { c: 3}} log(JSON.stringify(obj2)); // { a: 2, b: { c: 3}} // Deep Clone obj1 = { a: 0 , b: { c: 0}}; let obj3 = JSON.parse(JSON.stringify(obj1)); obj1.a = 4; obj1.b.c = 4; log(JSON.stringify(obj3)); // { a: 0, b: { c: 0}} } test();
同名属性的替换
对于这种嵌套的对象,一旦遇到同名属性,Object.assign
的处理方法是替换,而不是添加。
const target = { a: { b: 'c', d: 'e' } } const source = { a: { b: 'hello' } } Object.assign(target, source) // { a: { b: 'hello' } }