--- title: Object.assign() slug: Web/JavaScript/Reference/Global_Objects/Object/assign tags: - ECMAScript 2015 - JavaScript - Method - Object - Reference - polyfill - メソッド translation_of: Web/JavaScript/Reference/Global_Objects/Object/assign ---
{{JSRef}}
Object.assign() メソッドは、すべての{{jsxref("Object/propertyIsEnumerable", "列挙可能", "", 1)}}な{{jsxref("Object/hasOwnProperty", "自身のプロパティ", "", 1)}}の値を、1つ以上のコピー元オブジェクトからコピー先オブジェクトにコピーするために使用されます。
Object.assign(target, ...sources)
targetsourcesコピー先オブジェクトです。
コピー先オブジェクトのプロパティは、コピー元に同じ{{jsxref("Object/keys", "キー", "", 1)}}のプロパティがあると上書きされます。より後のコピー元のプロパティが、より前のものを同様に上書きします。
Object.assign() メソッドは、コピー元オブジェクトから列挙可能かつ直接所有のプロパティだけをコピー先オブジェクトにコピーします。この際、コピー元オブジェクトには [[Get]]、コピー先オブジェクトには [[Set]] を使いますので、ゲッターとセッターを呼び出すことになります。これはプロパティの代入であり、プロパティをコピーしたり新しく定義をしたりするのとは違います。そのため、コピー元にゲッターが存在する場合、新しいプロパティをプロトタイプにマージする用途には不適切でしょう。
プロパティ定義を (列挙可能属性も含めて) プロトタイプの中にコピーするには、このメソッドではなく {{jsxref("Object.getOwnPropertyDescriptor()")}} と {{jsxref("Object.defineProperty()")}} を使用してください。
{{jsxref("String")}} と {{jsxref("Symbol")}} の両方のプロパティがコピーされます。
エラーが発生した場合、例えばプロパティが書き込み不可の場合は、 {{jsxref("TypeError")}} が発生しますが、エラーが発生する前にプロパティが追加される場合、 target オブジェクトが変更されることがあります。
Note: Object.assign() はコピー元の値が {{jsxref("null")}} や {{jsxref("undefined")}} でも例外を投げないことに注意して下さい。
この{{Glossary("Polyfill","ポリフィル")}}は、 ES5 にシンボルがないため、シンボルのプロパティに対応していません。
if (typeof Object.assign !== 'function') {
// Must be writable: true, enumerable: false, configurable: true
Object.defineProperty(Object, "assign", {
value: function assign(target, varArgs) { // .length of function is 2
'use strict';
if (target === null || target === undefined) {
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 && nextSource !== undefined) {
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
});
}
const obj = { a: 1 };
const copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }
Object.assign() はプロパティの値をコピーするため、深い複製を行うには別な方法を使用する必要があります。
元の値がオブジェクトへの参照である場合、参照の値のみをコピーするからです。
function test() {
'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();
const o1 = { a: 1 };
const o2 = { b: 2 };
const o3 = { c: 3 };
const obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1); // { a: 1, b: 2, c: 3 }, コピー先オブジェクト自体が変化する
const o1 = { a: 1, b: 1, c: 1 };
const o2 = { b: 2, c: 2 };
const o3 = { c: 3 };
const obj = Object.assign({}, o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
プロパティは、引数の順でより後にあるオブジェクトが同じプロパティを持っていると上書きされます。
const o1 = { a: 1 };
const o2 = { [Symbol('foo')]: 2 };
const obj = Object.assign({}, o1, o2);
console.log(obj); // { a : 1, [Symbol("foo")]: 2 } (cf. bug 1207182 on Firefox)
Object.getOwnPropertySymbols(obj); // [Symbol(foo)]
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 }
const v1 = 'abc';
const v2 = true;
const v3 = 10;
const v4 = Symbol('foo');
const obj = Object.assign({}, v1, null, v2, undefined, v3, v4);
// プリミティブ値はラップされ、 null と undefined は無視される
// なお、文字列をラップした時だけ、直接所有で列挙可能なプロパティが存在する
console.log(obj); // { "0": "a", "1": "b", "2": "c" }
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
// target.foo に代入しようとすると、この例外が発生する
console.log(target.bar); // 2, 一番目のコピー元オブジェクトはコピーされている
console.log(target.foo2); // 3, 二番目のコピー元の最初のプロパティもコピーされている
console.log(target.foo); // 1, ここで例外が発生
console.log(target.foo3); // undefined, assign メソッドが終了したので foo3 はコピーされない
console.log(target.baz); // undefined, 三番目のコピー元もコピーされない
var obj = {
foo: 1,
get bar() {
return 2;
}
};
let copy = Object.assign({}, obj);
console.log(copy);
// { foo: 1, bar: 2 }
// copy.bar の値は obj.bar のゲッターの返値。
// 記述子を完全にコピーする代入関数
function completeAssign(target, ...sources) {
sources.forEach(source => {
let descriptors = Object.keys(source).reduce((descriptors, key) => {
descriptors[key] = Object.getOwnPropertyDescriptor(source, key);
return descriptors;
}, {});
// By default, Object.assign copies enumerable Symbols, too
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 } }
| 仕様書 |
|---|
| {{SpecName('ESDraft', '#sec-object.assign', 'Object.assign')}} |
{{Compat("javascript.builtins.Object.assign")}}