この記事は技術レビューを必要としています。ぜひご協力ください。
この記事は編集レビューを必要としています。ぜひご協力ください。
一つ以上の ソース オブジェクトから、直接所有で (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) | 未サポート | 未サポート | (有) |