【JavaScript】ディープコピーとシャローコピーの違い

更新日:2023/04/12

JavaScritpでオブジェクトをコピーするとき、理解しておく必要があるのがディープコピーとシャローコピーです。
この二つの違いを把握しておかないと、不具合を引き起こす可能性があります。

そこで今回は、ディープコピーとシャローコピーの違いについて簡単に解説します。

 

ディープコピーとは

一般的なオブジェクトのコピーに相当するのが、ディープコピーです。
コピー元または先のプロパティを変更しても、他方のプロパティに影響を与えません。

const originalObj = {
  value1 : 100,
  obj1: {
    value2:"abc",
  }
};
  // オブジェクトのディープコピー
const copyObj = structuredClone(originalObj);

originalObj.obj1.value2 = 10000;

console.log( originalObj );
  // 結果: { value1: 100, obj1: { value2: 10000 } }
console.log( copyObj );
  // 結果: { value1: 100, obj1: { value2: "abc" } }

上のコードはoriginalObjのプロパティを変更しています。
しかし、ディープコピー先のcopyObjはコピーされた値を保持しています。
つまり変更の影響を受けていません。

structuredClone()はオブジェクトをディープコピーするメソッドです。
次のページを読んでみてください。
【JavaScript】structuredClone()でオブジェクトのディープコピーをする方法

 

シャローコピーとは

シャローは『浅い』という意味があります。
シャローコピーだと、『浅いコピー』ですね。

シャローコピーは、コピー元または先のプロパティを変更すると、他方のプロパティに影響を与えることがあります。

const originalObj = {
  value1 : 100,
  obj1: {
    value2:"abc",
  }
};
  // オブジェクトのシャローコピー
const copyObj = Object.assign({},originalObj);

originalObj.value1 = "changed";
originalObj.obj1.value2 = 10000;

console.log( originalObj );
  // 結果: { value1: 'changed', obj1: { value2: 10000 } }
console.log( copyObj );
  // 結果: { value1: 100, obj1: { value2: 10000 } }

上のコードの結果を見ると、value1の変更は他方に影響を与えていません。
しかし、obj1.value2への変更は他方に影響を与えています。

初心者だととても不可解な現象を引き起こすのがシャローコピーです。

 

仕組みを理解しよう

とても不可解な現象を引き起こすシャローコピーですが、仕組みを理解すると納得できます。

シャローコピーの仕組み

シャローコピーは空のオブジェクトを作成して、コピー元のプロパティと同名のプロパティを作成します。
そして作成したプロパティに、コピー元の値をセットします。

実際はもっと考慮すべき点がありますが、イメージ的には次のようなコードになります。

const copyObj = {};
Object.entries( originalObj ).forEach(
  ([ propName , value ]) => copyObj[propName] = value
);

次にプロパティの値について考えてみます。
プロパティが持っている値は、実データではなくて、実データを特定するための値、つまり参照値のようなものです。
ここら辺の仕組みは仕様で定義されていないので、実装を組みこむベンダー側で効率の良い方法が選択されます。

プロパティと実データの関係

そして、代入や引数渡しなどは参照値をやりとりします。

代入や引数渡しなどは参照値をやりとり

これにより、シャロ―コピーしたオブジェクト間でプロパティ変更の影響はありません。

言っていることが矛盾しているような気がしますが…

オブジェクトも実データへの参照です。

オブジェクトも実データへの参照

プロパティ値を変更すると、実データ内のプロパティが変更されます。

実データ内のプロパティが変更される

そのため、他方に影響を与えたように見えるのです。

ディープコピーの仕組み

ディープコピーのディープは『深い』という意味です。
プロパティコピー中にオブジェクトがあったら、新規でオブジェクトを作成して深く深くコピーしていきます。

コピー中はオブジェクトのループにも注意する必要があります。
注意しないと無限ループするので。

なお関数オブジェクトなどコピーできないものもあるので、完全なコピーはできません。
ディープコピーをするときは、プロパティ値のみのシンプルなオブジェクトを想定した方がいいですね。

更新日:2023/04/12

書いた人(管理人):けーちゃん

スポンサーリンク

記事の内容について

null

こんにちはけーちゃんです。
説明するのって難しいですね。

「なんか言ってることおかしくない?」
たぶん、こんなご意見あると思います。

裏付けを取りながら記事を作成していますが、僕の勘違いだったり、そもそも情報源の内容が間違えていたりで、正確でないことが多いと思います。
そんなときは、ご意見もらえたら嬉しいです。

掲載コードについては事前に動作確認をしていますが、貼り付け後に体裁を整えるなどをした結果動作しないものになっていることがあります。
生暖かい視線でスルーするか、ご指摘ください。

ご意見、ご指摘はこちら。
https://note.affi-sapo-sv.com/info.php

 

このサイトは、リンクフリーです。大歓迎です。