JavaScript
es6
es2015

JavaScript(ES6/ES2015)でオブジェクトをコピーする時に注意すること

どうも、はぐっです・ω・♪

JavaScript(ES6/ES2015)でオブジェクトをコピー」

もう、babelを利用してES6/ES2015でJavaScriptを書いている人もだいぶ増えて来たことかと思います。で、様々な場面でオブジェクトを扱うことが多くあるはずっ。
んで、コピーしたいなんてこともあるはずっ。
そんなとき、コピーの仕方はいくつかあると思いますが、ここでは二つのやり方を。

コピーの方法

jQueryを利用してオブジェクトをコピー

JavaScript界の大ベテラン、「jQuery」
こいつに、オブジェクトをコピーする時に使えるメソッドが用意されています。
(本来の目的はオブジェクトのマージだったり。)

$.extend

使い方は

let firstObj = {
  a: 'a',
  b: {
    a: 'a',
    b: {
      a: 'a'
    }
  }
};

let secondObj = $.extend(true, {}, firstObj);

はいっ、こぴー。

引数はこちら。

第一引数       : ディープコピーかどうか(省略可)
第二引数       : マージのもととなるオブジェクト
第三引数以降 : マージするオブジェクト(いくつでも)

ん?
ディープコピー?

そう!
今回はここがポイントです!

ディープコピーとは

まぁ、「とは」っていうほど定義が必要なものではなくて、

deep:深い

つまり、深いコピーをするか、浅いコピーをするか。
下の階層まで再帰的にコピーするか。

ここ、割と大事。

ES6/ES2015を利用してオブジェクトをコピー

ES6/ES2015になって、
待ってましたー!!!!
な機能が様々追加され、いろいろとはっぴーになったわけですが、

その中の一つ。

Object.assign

こいつ。

使い方は

let firstObj = {
  a: 'a',
  b: {
    a: 'a',
    b: {
      a: 'a'
    }
  }
};

let secondObj = Object.assign({}, firstObj);

はいっ、こぴー。

第一引数       : マージのもととなるオブジェクト
第二引数以降 : マージするオブジェクト(いくつでも)

うむ。
さっきのjQueryのextendと使い方自体はそうかわら・・・

ディープは!?

そう、ここが違うのです。

Object.assignは、シャローコピー(ディープコピーと違って浅いコピー)なのです!!

これね、困る時があるんですよ。

コピーの方法による違い

例えば

let firstObj = {
  a: 'a',
  b: {
    a: 'a',
    b: {
      a: 'a'
    }
  }
};

があったとしてですよ。

$.extendの場合

let secondObj = $.extend(true, {}, firstObj);

secondObj.b.a = 2;

console.log(firstObj.b.a); // 1
console.log(secondObj.b.a); // 2

この場合、出力は

1: a
2: 2

となります。

Object.assignの場合

let secondObj = Object.assign({}, firstObj);

secondObj.b.a = 2;

console.log(firstObj.b.a); // 1
console.log(secondObj.b.a); // 2

この場合、出力は

1: 2
2: 2

となります。

ほらああああああああああ!!!

こういうところで違いがでてくるんですよ!

だから言ったじゃないですかあああ!

…こほん。

つまりね、

オブジェクトがプロパティとしてオブジェクトを持っている時、

シャローコピー(Object.assign)だと同じ参照
ディープコピー($.extend(true))だと別参照

となるわけですね。

みなさま、くれぐれもオブジェクトのコピーは慎重に。

ES6/ES2015のご利用は計画的に。