1.説明Object.assign
_
Object.assign()
メソッドは、すべての列挙可能な(Object.propertyIsEnumerable()
true を返す)独自の(Object.hasOwnProperty()
true を返す) プロパティを 1 つ以上のソース オブジェクトからターゲット オブジェクトにコピーし、変更されたオブジェクトを返します。
1.1 文法
Object.assign(target, ...sources) // 返回合并后的target的对象
target
ターゲット オブジェクト、つまりソース オブジェクトのプロパティを受け取るオブジェクトも、変更された戻り値になります。
source
マージするプロパティを含むソース オブジェクト。
2.申請Object.assign
_
2.1 基本的な例
let target = {
a: 1 };
let source = {
b: 1, c: 1 };
const final = Object.assign(target, source);
console.log(final); // {a: 1, b: 1, c: 1}
// 我们输出target 看看
console.log(target); // {a: 1, b: 1, c: 1}
対象オブジェクトも変更されていることが分かりますが、これを回避するにはどうすればよいですか? ディープコピー
let target = {
a: 1 };
let source = {
b: 1, c: 1 };
const final = Object.assign(JSON.parse(JSON.stringify(target)), source);
console.log(final);// {a: 1, b: 1, c: 1}
console.log(target);// {a: 1} 这样就不会改变target了
2.2 結合したオブジェクトに同じ属性が存在する場合
// 一个 source 时
let target = {
a: 1 };
let source = {
a: 100, b: 1, c: 1 };
const final = Object.assign(target, source);
console.log(final); // {a: 100, b: 1, c: 1}
// 两个source 时
let target = {
a: 1 };
let source = {
a: 100, b: 1, c: 1 };
let source1 = {
c: 100, d: 1 };
const final = Object.assign(target, source, source1);
console.log(final); // {a: 100, b: 1, c: 100, d: 1}
プロパティは、後続のパラメータで同じプロパティを持つ他のオブジェクトによって上書きされることがわかります。
2.3 代入参照問題
let source = {
a: 1,
b: {
c: 1,
},
};
const final = Object.assign({
}, source);
console.log(final); // { a: 1, b: { c: 1 } }
console.log(source);// { a: 1, b: { c: 1 } }
source.a = 2;
console.log(final);// { a: 1, b: { c: 1 } } 不变
console.log(source);// { a: 2, b: { c: 1 } } 变了
source.b.c = 2;
console.log(final); // { a: 1, b: { c: 2 } } 变了
console.log(source);// { a: 2, b: { c: 2 } } 变了
ソース オブジェクトはオブジェクトへの参照であり、その参照値をコピーするだけであることがわかります。ソース オブジェクトにオブジェクトが埋め込まれており、その値がソース オブジェクト内で変更されると、マージされた値も変更されます。
それを避けるにはどうすればよいでしょうか? JSON.parse(JSON.stringify(Object.assign({}, source))
ただそれを採用してください
2.4 例外により後続のコピータスクが中断される
let target = Object.defineProperty({
}, 'a', {
value: 1,
writable: false, // 不可写
});
try {
Object.assign(target, {
b: 1 }, {
a: 3 }, {
c: 1 });
} catch (e) {
console.log(e);
}
console.log(target.b); // 1
console.log(target.a); // 1
console.log(target.c); // undefined
割り当て中にエラーが発生した場合、たとえばプロパティが書き込み可能でない場合は、これがスローされます
TypeError
。例外がスローされる前にプロパティが追加されていた場合、target
オブジェクトは変更されます
2.5 では、オブジェクトの値がまたは の場合にエラーがスローされObject.assign()
ません。source
null
undefined
const final = Object.assign({
}, {
a: 1 }, undefined, {
b: 1 }, null);
console.log(final); // {a: 1, b: 1}
2.6 プロトタイプチェーン上のプロパティと列挙不可能なプロパティはコピーできません
//摘自MDN
const obj = Object.create(
{
foo: 1 },
{
// foo 在obj的原型链上
bar: {
value: 2, // bar 是一个不可枚举属性
},
baz: {
value: 3,
enumerable: true, // baz 是一个枚举属性
},
}
);
const copy = Object.assign({
}, obj);
console.log(copy); // { baz: 3 }
2.7 基本型はオブジェクトとしてパッケージ化されます
const obj = Object.assign({
}, 'happy');
console.log(obj); // {0: 'h', 1: 'a', 2: 'p', 3: 'p', 4: 'y'}
const obj = Object.assign({
}, 'happy', 'good', true, 10);
console.log(obj); // {0: 'g', 1: 'o', 2: 'o', 3: 'd', 4: 'y'} 注意与上面输出的前四个区别
注: 独自の列挙可能なプロパティを持つことができるのは文字列のみです。
2.8 コピーアクセサー
// 摘自MDN
const obj = {
foo: 1,
get bar() {
return 2;
}
};
let copy = Object.assign({
}, obj);
console.log(copy); // { foo: 1, bar: 2 }
// 这是一个复制完整描述符的赋值函数
function completeAssign(target, ...sources) {
sources.forEach(source => {
let descriptors = Object.keys(source).reduce((descriptors, key) => {
descriptors[key] = Object.getOwnPropertyDescriptor(source, key);
return descriptors;
}, {
});
// 默认情况下,对象,也分配可枚举符号的副本
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 } }