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

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

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

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

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

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

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

 

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

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

 

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

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

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

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

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

 

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

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

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

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

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

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

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

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

*訂正*

コメントでご指摘いただいた通り、Array.from は浅いコピーでした。なのでディープコピーという言葉を使うのは正しくなかったです。以下は コピー時に元配列に反映させない方法になります。

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

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

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

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

 

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

このコードを実行すると cloned  が original  の浅いコピー配列として作成されます。

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

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

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

 

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

もし配列代入を使ってしまうと、予想しない動作が起こるので要注意です。
意図的でない場合以外は基本的には Array.from  を使うのがほとんどだと思います。

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

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

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

 

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

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

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

ここまでのまとめ

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

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

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

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

Shareこの記事をシェアしよう!

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

2件のコメント
  • ほたち

    コメント失礼します。javascript初心者です。
    ここで紹介されている”シャローコピー”と”ディープコピー”は、いずれもシャローコピーであると思われます。
    ディープコピーとは配列に含まれる要素も別の参照に変わっていなければいけません。

    12月 11, 2019 12:07 pm
  • nbk

    シャローとディープは、直訳すれば浅いと深いかなと思います。
    説明としては、 シャローコピーは実体をコピーしない(参照)で、ディープコピーは実体をコピーする(クローン)みたいな感じの方がイメージしやすいのではと思います。

    6月 13, 2023 3:41 am

コメントを残す

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

CAPTCHA


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