JavaScriptで連想配列(オブジェクト)のコピーをする正しい方法

JavaScriptでよく使うデータ型と言えば連想配列(あるいはオブジェクトとも言う)

これをコピーする場合、間違った方法を使うとバグや不具合の原因になります。しかもエラーも出ないので自分でミスにも気づきにくいのが厄介な所です。

ここでは連想配列をコピーする本当に正しい方法とコード例についてまとめました。

連想配列コピーのNG例

まず連想配列コピーでやってはいけないNG例を紹介します。

それはある変数に連想配列をそのまま代入してしまうこと

これをやってしまうとコピー元とコピー先のデータが共有されてしまいます。

 

例えば次のように連想配列をコピーした(つもり)のコード例で考えてみましょう。

連想配列のコピー元が original  、コピー先が cloned  です。

コードとしては間違ってはいないですが、データそのものをコピーする場合は正しくありません。

 

どういう風に間違っているかは次のコードを実行してみれば分かるはず

コピー先の連想配列の値を変更した後 original  と cloned  をコンソール表示するコード例です。

表示結果はそれぞれ次の通り・・・

まず次がコピー元 original  のコンソール表示、

そして次がコピー先 cloned  のコンソール表示

・・・見てわかるように両方とも同じ内容に書き換わってしまっています。

 

こうなる理由は連想配列のコピーのされ方に次の2種類があるため

  • 浅い(シャロー)コピー【Shallow Copy】
  • 深い(ディープ)コピー【Deep Copy】

浅いコピーの場合はオブジェクトの参照(データの置き場所)が共有されてしまうのに対し、深いコピーの場合は内部のデータそのものまで全部コピーされます。

コード例のようにただ代入でコピーしてしまうと浅いコピーが起きてしまうので、一方を変更すると両方に変更が反映されてしまうという訳です。

なので完全に連想配列をコピーするにはディープコピーする必要があります。

連想配列をディープコピーするには

ではどうやって連想配列をディープコピーするのか・・・ということですがやり方は簡単

それは Object.create  という連想配列専用のメソッドを使うことです。

例えばコピー元を original  とすれば次のように書けばOK

これで cloned  が original  のディープコピーになります。

 

例えば次が Object.create  を使って連想配列をコピーしているコード例

先ほどのコードと同じく original  と cloned  をコンソール表示しています。

このコードを実行したときの結果はそれぞれ次の通り・・・

まず次がコピー元の連想配列 original  のコンソール表示、

そして次がコピー先の連想配列 cloned  のコンソール表示

・・・今度は無事 cloned  の変更が original  に影響を与えないようになりました。

 

以上が連想配列をディープコピーする方法です。

浅いコピーは意図的でない限りほとんど使わないので基本的にはディープコピーした方がバグや不具合の温床になりにくいと思います。

配列をコピーする場合もディープコピーが必要

ここまでで連想配列をコピーする方法についてまとめてきました。

コピー種類にはシャローとディープの2種類があり、データも含めて完全にコピーするにはディープコピーが必要なことを忘れないようにしたいですね。

 

ちなみに配列を完全コピーする場合もディープコピーが必要になります。

そのやり方やコード例は次でまとめた通り

連想配列と同じく配列コピーする場合もコピー方法には要注意です。

ここまでのまとめ

ということで連想配列のコピー方法まとめ

  • 代入でコピーすると浅いコピーになる
    連想配列を別屁数に直接代入すると浅いコピー(Shallow Copy)になってしまう。
    参照が同じなので一方を変更するともう一方も変更されてしまう点に要注意!
  • Object.createを使えば深いコピーになる
    連想配列内のデータも含め全部コピーするには Object.create  を使うことが必要
    参照が別々になるので一方が変更されてももう一方に影響を及ぼさない

場合によっては意図的に浅いコピーが必要になる場面もあるかもしれません。

しかし基本的には Object.create  を使うのが確実で安全な方法だと思います。

以上JavaScriptで連想配列をコピーする方法についてでした。

Commentsこの記事についたコメント

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA


このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください