JavaScriptで配列をコピーする”本当に”正しい方法

JavaScriptで注意が必要なことの1つが配列やオブジェクトのコピーです。

間違った方法でコピーしてしまうと予期せぬ動作やバグの原因にもなりかねません。

そこでここでは配列を完全にコピーするための本当に正しい方法を解説します。

配列をコピーするときにやりがちなNG例

まず配列コピーで絶対してはいけないNG例を紹介します。

そのNG例とは配列を別の変数にそのまま代入してしまうこと

 

例えば次のように配列をコピーしている(つもり)のコード例があるとしましょう。

上コードでは cloned = original;  のように別変数に配列を代入しています。一見正しそうですが実は全く意味をなさない間違ったコードです。

 

本当に間違えているかは次のコードを書いて実行してみれば分かるはず

コピー先の配列 cloned  を書き換え、 original  と cloned  の両方をコンソール表示しています。

そして次がコンソール表示された original  の内容、

そして次がコンソール表示された cloned  の内容

・・・見てわかるように cloned  の変更が original  には反映されちゃってます。

 

こうなる理由は代入によって浅いコピーShallow Copy)が起きてしまったためです。

普通の数値などの変数の場合、別変数に代入すれば完全に別物として扱われます。しかし配列(あるいはオブジェクト)の場合はコピーと言っても・・・

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

・・・の2種類があります。

シャローコピーの場合はオリジナル配列とクローン配列は同じ参照(データのある場所)を共有しているにすぎません。そのため一方を変更すればもう一方も変更されてしまうという訳です。

ここら辺はポインタの概念がある言語(例えばC言語など)を学べば分かりやすいですが、そういうものだと思っておけば問題ありません。

なので結論としては完全に配列をコピーするにはディープコピーする必要があるという訳です。

配列を深い(ディープ)コピーするには

ではJavaScriptで配列をディープコピーするにはどうすればいいか・・・

という話ですが Array.from  という配列専用のコピーメソッド を使えばOKです。

使い方はコピー元の配列を original  として次のように書くだけ

これで cloned  が original  のディープコピーとして作成されます。

 

例えば次は Array.from  を使い配列をコピーし、コピー元・先をコンソール表示するコード例

このコードを実行すると cloned  が original  から独立した配列として作成されます。

そして次がコピー元の配列 original  のコンソール表示、

そして次がコピー先の配列 cloned  のコンソール表示です。

・・・今度は無事 cloned  の変更が original  に反映されないようになりました。

 

配列をコピーするときはこの例のようにディープコピーしてあげれば問題ありません。

もしシャローコピーした場合、予想もしない動作が起こることもあるので要注意です。意図的でない場合以外は基本的にはディープコピーを使うのがほとんどだと思います。

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

ここまでで配列のコピー方法についてまとめてきました。

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

 

そして配列同様、連想配列(オブジェクト)の場合も完全コピーにディープコピーが必要になります。

その詳しいやり方やコード例は次記事でまとめた通り

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

ここまでのまとめ

ということで配列をコピーする方法まとめ

  • コピーにシャローコピーを使ってはダメ
    浅いコピーだとコピー元とコピー先の参照(データのある場所)が共有されてしまう
    そのため一方を変更するともう一方も変更されてしまうことに要注意!
  • コピーは基本ディープコピーを使う
    配列の場合、ディープコピーするには Array.from  を使えばOK
    使用することでコピー元とコピー先の配列が完全に別のものとして扱える

浅いコピー(シャローコピー)が必要になる場面はあまりないと思います。

なので配列コピーする場合はディープコピーを使うのが安全です。

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

コメントを残す

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

CAPTCHA


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