🐈
mapメソッドで新しく生成した配列がシャローコピーになる
シャロコピーとディープコピーについて下記の記事を参照
問題無い例
export interface ArrayTest {
key: string;
}
export interface Test {
id: number;
text: string;
array: ArrayTest[];
}
const addData = {
id: 1, text: 'test',array:[{key:'keyTest'}]
}
const data: Array<Test> = [];
data.push(addData);
let newData = data.map((data: Test) => ({ ...data }));
console.log(newData[0]['text']); // test
console.log(data[0]['text']); // test
newData[0]['text'] = 'aaa';
console.log(newData[0]['text']); // aaa
console.log(data[0]['text']); // test
問題ある例
export interface ArrayTest {
key: string;
}
export interface Test {
id: number;
text: string;
array: ArrayTest[];
}
const addData = {
id: 1, text: 'test',
array:[{key:'keyTest'}]
}
const data: Array<Test> = [];
data.push(addData);
let newData = data.map((data: Test) => ({ ...data }));
console.log(newData[0]['array'][0]['key']); // keyTest
console.log(data[0]['array'][0]['key']); // keyTest
newData[0]['array'][0]['key'] = 'bbb';
console.log(newData[0]['array'][0]['key']); // bbb 両方とも値が変わる
console.log(data[0]['array'][0]['key']); // bbb 両方とも値が変わる
配列の中に配列がある入れ子状態だと、その配列の中の配列は参照渡しになってしまうので
新規に作成した配列の値を変更すると、元の値にも影響を及ぼす。
## 対処法はmapを使わずに新規にJSONオブジェクトを作成して対応する
古い対処法
const newData = JSON.parse(JSON.stringify(data));
対処法はstructuredCloneを使用する
const newData = structuredClone(data);
引用元
mapは新規に配列を作成するので元の配列に影響を与えないという先入観があり
ロクにコードを確認せずにテストしてみたら
妙な挙動をしたので調べてみたらこういうことだった。
記事を訂正
2024/11/02
Discussion
既存の配列インスタンスに対して破壊的操作を行った為では?参照渡しは変数への代入に対する話なので
失礼致しました。そのようなことではないみたいです。
シャローコピーディープコピーという概念でした。
この記事を書いている際には、シャローコピーとディープコピーという概念を知らずでした。
シャロコピーディープコピーについて structuredCloneについて