Skip to content

JavaScript の配列のシャローコピーに使えるメソッド3つ(+ 1つ)とその使い分け

代入演算子ではコピーできない

有名な話ですが、JavaScript では配列を “=” (代入演算子)で別の変数に格納しても参照渡しとなってしまい、コピー(複製)することができません。

配列をコピーする方法

利用可能なメソッド

代入演算子ではなく次のようなメソッドを利用することでコピーを作成できます。

  • slice メソッド
  • concat メソッド
  • Array.from メソッド

またこれらのメソッド以外にも、次の方法でコピーを作成することもできます。

  • スプレッド演算子

どれを使うべきか

書きやすさ、読みやすさ、パフォーマンス、ブラウザの実装状況などを考慮すると、slice メソッドを使う方法がオススメです。

ただし、slice メソッドをコピー目的で使う場合、上で紹介したように引数を空にする以外にも、array.slice(0); としたり、array.slice(0, array.length); というような書き方をすることもできてしまうので、「コピー目的で使うときには引数を空にする」といったルールを設け、作業者間でズレが生じないようにしておくとよいです。

なお、メソッドの持つ本来の意味を考えると Array.from メソッドやスプレッド演算子を使いたいところですが、どちらも IE で動作しなかったり、配列をコピーする目的で使っていることを推測しにくかったりするので、あまりオススメできません。

※ Array.from メソッドやスプレッド演算子を使う場合も、引数が配列であることが分かればコピーに使っていることを推測できるのですが、引数が配列なのかどうかはソースを見ないとわからないことが多いです。

シャローコピーとディープコピー

上で紹介した方法で作られるコピーは「シャローコピー」と呼ばれるもので、1階層だけの”浅い”コピーとなっています。

2階層目以降のオブジェクトは参照渡しの状態になっているため、2階層目以降を変更するとコピー先、コピー元両方が変更されます。

シャローコピーに対し、完全なコピーはディープコピーと言われるのですが、このディープコピーはなかなか実装が難しく、いまのところベストプラクティスは無いのではないかと思います。

どうしても必要な場合、文字列や数値だけを含むような単純な多次元配列であれば、一度 JSON.stringify で json 化してそれを改めて JSON.parse することでディープコピーを実現することが可能です。

まとめ

配列のコピーに使える方法をいくつか紹介しましたが、とくに slice と concat はコピーを目的としたメソッドではないため、他の人がソースの意図を汲み取れない恐れがあります。

そのため、プロジェクトで「コピー目的では引数のない sliceを使う」などのルールを設定して混乱が生じないように気をつけましょう。

おまけ:要素の追加、更新、削除

配列に対する追加、削除には、すでに push, splice といったメソッドが用意されていますが、これらのメソッドは変更メソッドなので、元となる配列そのものを変更してしまいます。

そのため、例えば Redux の Store の更新など、元の配列の変更を許されていない場合には使うことができません。

そういった場合にオススメなのが findIndex と […array], slice を活用した書き方で、一貫性のある書き方をすることができます。

そのままでは IE で動作しませんので、Babel など各種トランスパイラを利用する必要があります。

 

Comments are closed.