Object.assign()
Baseline
Widely available
This feature is well established and works across many devices and browser versions. Itâs been available across browsers since 2015å¹´9æ.
Object.assign() 被ç¨ä¾è¤è£½ä¸åæå¤åç©ä»¶èªèº«ææå¯æ¸ç屬æ§å°å¦ä¸åç®æ¨ç©ä»¶ãåå³çå¼çºè©²ç®æ¨ç©ä»¶ã
èªæ³
Object.assign(target, ...sources)
忏
åå³å¼
åä½µç®æ¨ç©ä»¶å(å¤å)便ºç©ä»¶æå¾å°çæçµç©ä»¶ã
說æ
妿å¨ç®æ¨ç©ä»¶è£¡ç屬æ§å稱(key)å便ºç©ä»¶ç屬æ§å稱ç¸åï¼å°æè¢«è¦å¯«ãè¥ä¾æºç©ä»¶ä¹éåæç¸åç屬æ§å稱ï¼åå¾è æå°åè è¦å¯«ã
Object.assign()åªæå¾ä¾æºç©ä»¶å°èªèº«å¯åèç屬æ§è¤è£½å°ç®æ¨ç©ä»¶ãæ¤å½å¼æ¹æ³(method) 使ç¨ä¾æºç©ä»¶ç[[Get]]äºä»¶åç®æ¨ç©ä»¶ç[[Set]]äºä»¶ï¼ä½¿å®å°æå·è¡ getters å settersãå æ¤ï¼ééçææ´¾(assigns)屬æ§ä¸åªæ¯è¤è£½æå®ç¾©æ°å±¬æ§ãè¥å¨åä½µå
å« getters ç便ºç©ä»¶æï¼éåäºä»¶å¯è½å°±ä¸é©åç¨ä¾å併屬æ§ãè³æ¼è¤è£½å±¬æ§çå®ç¾©(å
å«å
¶å¯åèæ§)å°å屬æ§ï¼å忝æç¨å° Object.getOwnPropertyDescriptor() å Object.defineProperty() ã
String å Symbol é¡åç屬æ§é½æè¢«è¤è£½ã
è¥ç¼çé¯èª¤ï¼ä¾å¦: ç¶ä¸å屬æ§ä¸å¯è¢«å¯«å
¥æï¼å°æå¼ç¼ TypeError çé¯èª¤ï¼ä¸ç®æ¨ç©ä»¶å©é¤ç屬æ§å°ä¸ææ¹è®ã
注æ: Object.assign() 䏿å¨ä¾æºç©ä»¶å±¬æ§çå¼çºnull æ undefined çæåæåºé¯èª¤ã
ç¯ä¾
>è¤è£½ç©ä»¶
var obj = { a: 1 };
var copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }
è¦å:éæ·±å±¤è¤è£½
深層è¤è£½(deep clone)éè¦ä½¿ç¨å
¶ä»çæ¿ä»£æ¹æ¡ï¼å çº Object.assign() å
è¤è£½å±¬æ§å¼ãè¥ä¾æºç©ä»¶çå¼åç
§å°ä¸ååç©ä»¶ï¼å®åªæè¤è£½è©²åç©ä»¶çåç
§ã
function test() {
let a = { b: { c: 4 }, d: { e: { f: 1 } } };
let g = Object.assign({}, a); // 淺層
let h = JSON.parse(JSON.stringify(a)); // 深層
console.log(g.d); // { e: { f: 1 } }
g.d.e = 32;
console.log("g.d.e set to 32."); // g.d.e set to 32.
console.log(g); // { b: { c: 4 }, d: { e: 32 } }
console.log(a); // { b: { c: 4 }, d: { e: 32 } }
console.log(h); // { b: { c: 4 }, d: { e: { f: 1 } } }
h.d.e = 54;
console.log("h.d.e set to 54."); // h.d.e set to 54.
console.log(g); // { b: { c: 4 }, d: { e: 32 } }
console.log(a); // { b: { c: 4 }, d: { e: 32 } }
console.log(h); // { b: { c: 4 }, d: { e: 54 } }
}
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 }ï¼å±¬æ§cçºo3.cçå¼ï¼æå¾ä¸ååºç¾ç屬æ§cã
ææçå±¬æ§æè¢«å¾æ¹ç¸å屬æ§å稱çå¼è¦å¯«ã
è¤è£½ 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 æ¯ obj ç屬æ§éã
bar: {
value: 2, // bar æ¯ä¸å¯åèç屬æ§ï¼å çºenumerableé è¨çºfalseã
},
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 æ¯ read-only (å¯è®)屬æ§
Object.assign(target, { bar: 2 }, { foo2: 3, foo: 3, foo3: 3 }, { baz: 4 });
// TypeError: "foo" æ¯ read-only
// å¨ææ´¾å¼çµ¦ target.foo æï¼ç°å¸¸(Exception)æè¢«æåºã
console.log(target.bar); // 2, 第ä¸å便ºç©ä»¶è¤è£½æåã
console.log(target.foo2); // 3, 第äºå便ºç©ä»¶ç第ä¸å屬æ§è¤è£½æåã
console.log(target.foo); // 1, ç°å¸¸å¨é裡æåºã
console.log(target.foo3); // undefined, è¤è£½ç¨å¼å·²ä¸æ·ï¼è¤è£½å¤±æã
console.log(target.baz); // undefined, 第ä¸å便ºç©ä»¶ä¹ä¸æè¢«è¤è£½ã
è¤è£½çååç¨åº
var obj = {
foo: 1,
get bar() {
return 2;
},
};
var copy = Object.assign({}, obj);
console.log(copy);
// { foo: 1, bar: 2 }ï¼ copy.barçå¼ï¼æ¯obj.barçgetteråå³çå¼ã
// éåå½å¼ç¨ä¾è¤è£½å®æ´çæè¿°å
§å®¹ã
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 é è¨æè¤è£½å¯åèç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") {
Object.assign = function (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;
};
}
è¦æ ¼
| Specification |
|---|
| ECMAScript® 2027 Language Specification> # sec-object.assign> |