Object.assign() メソッドは、すべての列挙可能なプロパティの値を、1つ以上のコピー元オブジェクトからコピー先オブジェクトにコピーするために使用されます。戻り値としてコピー先オブジェクトを返します。

構文

Object.assign(target, ...sources)

引数

target
コピー先オブジェクト
sources
コピー元オブジェクト

返値

コピー先オブジェクトです。

解説

コピー先オブジェクトのプロパティは、コピー元に同じ名前のプロパティがあると上書きされます。より後のコピー元のプロパティが、より前のものを同様に上書きします。

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

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

エラーが発生した場合、例えばプロパティが書き込み不可の場合は、 TypeError が発生しますが、エラーが発生する前にプロパティが追加される場合、コピー先オブジェクトが変更されることがあります。

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

オブジェクトの複製

var obj = { a: 1 };
var 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();

オブジェクトの合成

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 }, コピー先オブジェクト自体が変化する

同じプロパティを持つオブジェクトの合成

var o1 = { a: 1, b: 1, c: 1 };
var o2 = { b: 2, c: 2 };
var o3 = { c: 3 };

var obj = Object.assign({}, o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }

プロパティは、引数の順でより後にあるオブジェクトが同じプロパティを持っていると上書きされます。

シンボル型のプロパティのコピー

var o1 = { a: 1 };
var o2 = { [Symbol('foo')]: 2 };

var obj = Object.assign({}, o1, o2);
console.log(obj); // { a : 1, [Symbol("foo")]: 2 } (cf. bug 1207182 on Firefox)
Object.getOwnPropertySymbols(obj); // [Symbol(foo)]

プロトタイプチェーン上のプロパティと列挙可能ではないプロパティはコピー不可

var obj = Object.create({ foo: 1 }, { // foo は obj のプロトタイプチェーン
  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,
  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;
  }
};

var 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;
}

var copy = completeAssign({}, obj);
console.log(copy);
// { foo:1, get bar() { return 2 } }

ポリフィル

このポリフィルは、 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) { // TypeError if undefined or null
        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) { // Skip over if undefined or null
          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
  });
}

仕様書

仕様書 状態 備考
ECMAScript Latest Draft (ECMA-262)
Object.assign の定義
ドラフト  
ECMAScript 2015 (6th Edition, ECMA-262)
Object.assign の定義
標準 初回定義

ブラウザーの対応

Update compatibility data on GitHub
デスクトップモバイルサーバー
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewAndroid 版 ChromeEdge MobileAndroid 版 FirefoxAndroid 版 OperaiOSのSafariSamsung InternetNode.js
基本対応Chrome 完全対応 45Edge 完全対応 ありFirefox 完全対応 34IE 未対応 なしOpera 完全対応 32Safari 完全対応 9WebView Android 未対応 なしChrome Android 完全対応 45Edge Mobile 完全対応 ありFirefox Android 完全対応 34Opera Android 未対応 なしSafari iOS 完全対応 ありSamsung Internet Android 完全対応 5.0nodejs 完全対応 4.0.0

凡例

完全対応  
完全対応
未対応  
未対応

関連情報

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

最終更新者: mfuji09,