オブジェクト・配列でコピーしたものに変更をかけるとコピー元も変わってしまう問題がありました。
それを解決する方法で最近structuredCloneを知ったので、今までのコピーの問題点を挙げながらご紹介いたします。
=でコピーする
=でコピーするとcopyArrayもarrayと同じ値が入ります。
const array = [1, 2, 3];
const copyArray = array;
console.log(array); // [1, 2, 3]
console.log(copyArray); // [1, 2, 3]
ここでcopyArrayの値を変えてみましょう。
const array = [1, 2, 3];
const copyArray = array;
copyArray[0] = 10;
console.log(array); // [10, 2, 3]
console.log(copyArray); // [10, 2, 3]
コピー元のarrayも変わってしまいます。
この=のコピーはコピー元を参照しているので、どちらも変わってしまいます。
逆も同様で、arrayの値を変えるとコピーしたcopyArrayも変わってしまいます。
const array = [1, 2, 3];
const copyArray = array;
array[2] = 30;
console.log(array); // [1, 2, 30]
console.log(copyArray); // [1, 2, 30]
スプレッド構文でコピーする
スプレッド構文とは
スプレット構文は配列やオブジェクトを展開する構文です。
const array = [1, 2, 3];
console.log(array); // [1, 2, 3]
console.log(...array); // 1 2 3
スプレッド構文でコピー
これを使って新たな配列を作ることでコピー元を参照しなくなるので、値を更新することができます。
const array = [1, 2, 3];
const copyArray = [...array];
copyArray[0] = 10;
console.log(array); // [1, 2, 3]
console.log(copyArray); // [10, 2, 3]
スプレッド構文でも問題がある
深いところ(2次元以上)だとコピー元を参照してしまいます。
これをシャローコピーといいます。
const array = [1, 2,[3, 4]];
const copyArray = [...array];
copyArray[2][0] = 33;
copyArray[2][1] = 44;
console.log(array); // [1, 2, [33,44]]
console.log(copyArray); // [1, 2, [33,44]]
深いところもコピー(ディープコピー)できるようにする方法があります。
structuredCloneが一番最適解
structuredCloneを使うとディープコピーされ、コピー元を参照しなくなるのでよいです。
const array = [1, 2,[3, 4]];
const copyArray = structuredClone(array);
copyArray[2][0] = 33;
copyArray[2][1] = 44;
console.log(array); // [1, 2, [3,4]]
console.log(copyArray); // [1, 2, [33,44]]
【余談】JSON.parse,JSON.stringifyでもディープコピーできる
JSON.parse,JSON.stringify
配列であったarrayをJSON.stringifyを使って文字列に変換します。
その変更した文字列をJSON.parseで配列に変換することで元の配列を参照できなくなるのでディープコピーすることができます。
const array = [1, 2,[3, 4]];
const copyArray = JSON.parse(JSON.stringify(array));
copyArray[2][0] = 33;
copyArray[2][1] = 44;
console.log(array); // [1, 2, [3,4]]
console.log(copyArray); // [1, 2, [33,44]]
個人的な問題点
これでも問題ないのですが、これぱっと見てなんでわざわざこんなことしているのかわからないのです。
加えてstructuredCloneを見てしまうとこれは文字数が多く、無理やり感が否めません。
まとめ
オブジェクト・配列のコピーはディープコピーであるstructuredCloneを使うことを推奨します。
なんとなくcloneが入っていることからコピーしているのかなっと予測できるので見やすさ的にもよいと思います。