この記事は技術レビューを必要としています。ぜひご協力ください。
この記事は編集レビューを必要としています。ぜひご協力ください。
一つ以上の ソース オブジェクトから、直接所有で (own) 列挙可能な (enumerable) すべてのプロパティの値を、ターゲット オブジェクトへコピーします。戻り値はターゲット オブジェクトです。
構文
Object.assign(target, ...sources)
引数
target- ターゲットオブジェクト
sources- ソースオブジェクト
戻り値
ターゲットオブジェクト
説明
Object.assign()メソッドは、ソース オブジェクトから列挙可能 (enumerable)かつ直接所有 (own)のプロパティだけをターゲット オブジェクトにコピーします。この際、ソース オブジェクトには[[Get]]、ターゲット オブジェクトには[[Set]]を使いますので、getterとsetterを呼び出すことになります。これはプロパティの 代入 (assign)であり、プロパティをコピーしたり新しく定義をしたりするのとは違います。そのため、ソースにgetterが存在する場合、新しいプロパティをプロトタイプにマージする目的には不適切でしょう。プロパティ定義を 列挙可能 (enumerable) 属性も含めてプロトタイプの中にコピーするには、 このメソッドではなく 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 }
オブジェクトをマージする
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 }, targetオブジェクト自身も変化する
シンボル型プロパティをコピーする
var o1 = { a: 1 };
var o2 = { [Symbol('foo')]: 2 };
var obj = Object.assign({}, o1, o2);
console.log(obj); // { a: 1, [Symbol("foo")]: 2 }
プロトタイプチェーン上のプロパティや列挙不可能なプロパティはコピーされない
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,
writeable: false
}); // target.fooはread-onlyなプロパティ
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;
}
};
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 は列挙可能なシンボルもコピーします。
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') {
(function () {
Object.assign = function (target) {
'use strict';
if (target === undefined || target === null) {
throw new TypeError('Cannot convert undefined or null to object');
}
var output = Object(target);
for (var index = 1; index < arguments.length; index++) {
var source = arguments[index];
if (source !== undefined && source !== null) {
for (var nextKey in source) {
if (Object.prototype.hasOwnProperty.call(source, nextKey)) {
output[nextKey] = source[nextKey];
}
}
}
}
return output;
};
})();
}
仕様
| 仕様 | 策定状況 | コメント |
|---|---|---|
| ECMAScript 2015 (6th Edition, ECMA-262) Object.assign の定義 |
標準 | Initial definition. |
| ECMAScript 2017 Draft (ECMA-262) Object.assign の定義 |
ドラフト |
ブラウザ実装状況
| 機能 | Chrome | Firefox (Gecko) | Internet Explorer | Edge | Opera | Safari |
|---|---|---|---|---|---|---|
| 基本サポート | 45 | 34 (34) | 未サポート | (有) | 32 | 9 |
| 機能 | Android | Chrome for Android | Firefox Mobile (Gecko) | IE Mobile | Opera Mobile | Safari Mobile |
|---|---|---|---|---|---|---|
| 基本サポート | 未サポート | 45 | 34.0 (34) | 未サポート | 未サポート | (有) |