Object.assign()

この記事は技術レビューを必要としています。ぜひご協力ください

この記事は編集レビューを必要としています。ぜひご協力ください

一つ以上の ソース オブジェクトから、直接所有で (own)  列挙可能な (enumerable) すべてのプロパティの値を、ターゲット オブジェクトへコピーします。戻り値はターゲット オブジェクトです。

構文

Object.assign(target, ...sources)

引数

target
ターゲットオブジェクト
sources
ソースオブジェクト

戻り値

ターゲットオブジェクト

説明

Object.assign()メソッドは、ソース オブジェクトから列挙可能 (enumerable)かつ直接所有 (own)のプロパティだけをターゲット オブジェクトにコピーします。この際、ソース オブジェクトには[[Get]]、ターゲット オブジェクトには[[Set]]を使いますので、getterとsetterを呼び出すことになります。これはプロパティの 代入 (assign)であり、プロパティをコピーしたり新しく定義をしたりするのとは違います。そのため、ソースにgetterが存在する場合、新しいプロパティをプロトタイプにマージする目的には不適切でしょう。プロパティ定義を 列挙可能 (enumerable) 属性も含めてプロトタイプの中にコピーするには、 このメソッドではなく Object.getOwnPropertyDescriptor()Object.defineProperty() を使うべきです。

StringSymbol 両方のプロパティがコピーされます。

エラーが発生した場合(例えばプロパティが書き込み不可)、 TypeError が発生し、ターゲット オブジェクトは変更されません。

Object.assign()はソースの値が nullundefined でも例外を投げないことに注意して下さい。

オブジェクトを複製する

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) 未サポート 未サポート (有)

関連情報

ドキュメントのタグと貢献者

 このページの貢献者: sapics, taiyaki32p, lv7777, saneyuki_s, shide55
 最終更新者: sapics,