链接:https://blog.csdn.net/wang252949/article/details/79106160
语法
Object.assign(target, ...sources)
参数
target
- 目标对象。
sources
- 源对象。
返回值
目标对象。
描述
如果目标对象中的属性具有相同的键,则属性将被源中的属性覆盖。后来的源的属性将类似地覆盖早先的属性。
Object.assign
方法只会拷贝源对象自身的并且可枚举的属性到目标对象。该方法使用源对象的[[Get]]
和目标对象的[[Set]]
,所以它会调用相关 getter 和 setter。因此,它分配属性,而不仅仅是复制或定义新的属性。如果合并源包含getter,这可能使其不适合将新属性合并到原型中。为了将属性定义(包括其可枚举性)复制到原型,应使用Object.getOwnPropertyDescriptor()
和Object.defineProperty()
。
在出现错误的情况下,例如,如果属性不可写,会引发TypeError
,如果在引发错误之前添加了任何属性,则可以更改target
对象。
注意,Object.assign
会跳过那些值为 null
或 undefined
的源对象。
示例
复制一个对象
-
var obj = { a: 1 };
-
var copy = Object.assign({}, obj);
-
console.log(copy); // { a: 1 }
深拷贝问题
针对深拷贝,需要使用其他方法,因为 Object.assign()
拷贝的是属性值。假如源对象的属性值是一个指向对象的引用,它也只拷贝那个引用值。
-
functiontest(){
-
'use strict';
-
-
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 Clone
-
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}}
-
}
-
-
test();
合并对象
-
var o1 = { a: 1 };
-
var o2 = { b: 2 };
-
var o3 = { c: 3 };
-
-
var obj = Object.assign(o1, o2, o3);
-
console.log(obj); // { a: 1, b: 2, c: 3 }
-
console.log(o1); // { a: 1, b: 2, c: 3 }, 注意目标对象自身也会改变。
合并具有相同属性的对象
-
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); // { a: 1, b: 2, c: 3 }
属性被后续参数中具有相同属性的其他对象覆盖。
拷贝 symbol 类型的属性
-
var o1 = { a: 1 };
-
var o2 = { [Symbol('foo')]: 2 };
-
-
var obj = Object.assign({}, o1, o2);
-
console.log(obj); // { a : 1, [Symbol("foo")]: 2 } (cf. bug 1207182 on Firefox)
-
Object.getOwnPropertySymbols(obj); // [Symbol(foo)]
继承属性和不可枚举属性是不能拷贝的
-
var obj = Object.create({foo: 1}, { // foo 是个继承属性。
-
bar: {
-
value: 2 // bar 是个不可枚举属性。
-
},
-
baz: {
-
value: 3,
-
enumerable: true // baz 是个自身可枚举属性。
-
}
-
});
-
-
var copy = Object.assign({}, obj);
-
console.log(copy); // { baz: 3 }
原始类型会被包装为对象
-
var v1 = "abc";
-
var v2 = true;
-
var v3 = 10;
-
var v4 = Symbol("foo")
-
-
var obj = Object.assign({}, v1, null, v2, undefined, v3, v4);
-
// 原始类型会被包装,null 和 undefined 会被忽略。
-
// 注意,只有字符串的包装对象才可能有自身可枚举属性。
-
console.log(obj); // { "0": "a", "1": "b", "2": "c" }
异常会打断后续拷贝任务
-
var 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,第三个源对象更是不会被拷贝到的。
拷贝访问器
-
var obj = {
-
foo: 1,
-
get bar() {
-
return 2;
-
}
-
};
-
-
var copy = Object.assign({}, obj);
-
// { foo: 1, bar: 2 }
-
// copy.bar的值来自obj.bar的getter函数的返回值
-
console.log(copy);
-
-
// 下面这个函数会拷贝所有自有属性的属性描述符
-
functioncompleteAssign(target,...sources){
-
sources.forEach(source => {
-
let descriptors = Object.keys(source).reduce((descriptors, key)=> {
-
descriptors[key] = Object.getOwnPropertyDescriptor(source, key);
-
return descriptors;
-
}, {});
-
-
// Object.assign 默认也会拷贝可枚举的Symbols
-
Object.getOwnPropertySymbols(source).forEach(sym => {
-
let descriptor = Object.getOwnPropertyDescriptor(source, sym);
-
if (descriptor.enumerable) {
-
descriptors[sym] = descriptor;
-
}
-
});
-
Object.defineProperties(target, descriptors);
-
});
-
return target;
-
}
-
-
var copy = completeAssign({}, obj);
-
console.log(copy);
-
// { foo:1, get bar() { return 2 } }
Polyfill
此polyfill不支持 symbol 属性,因为ES5 中根本没有 symbol :
-
if (typeof Object.assign != 'function') {
-
// Must be writable: true, enumerable: false, configurable: true
-
Object.defineProperty(Object, "assign", {
-
value: functionassign(target, varArgs){ // .length of function is 2
-
'use strict';
-
if (target == null) { // TypeError if undefined or null
-
throw new TypeError('Cannot convert undefined or null to object');
-
}
-
-
var to = Object(target);
-
-
for (var index = 1; index < arguments.length; index++) {
-
var nextSource = arguments[index];
-
-
if (nextSource != null) { // Skip over if undefined or null
-
for (var nextKey in nextSource) {
-
// Avoid bugs when hasOwnProperty is shadowed
-
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
-
to[nextKey] = nextSource[nextKey];
-
}
-
}
-
}
-
}
-
return to;
-
},
-
writable: true,
-
configurable: true
-
});
-
}