たまにはまじめなドリーマーday's

普段はやんちゃな悪ふざけドリーマーが、たまーにまじめになって書きおろす開発者の苦悩と閃き

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のご利用は計画的に。