🐈

mapメソッドで新しく生成した配列がシャローコピーになる

に公開
2

シャロコピーとディープコピーについて下記の記事を参照

https://zenn.dev/luvmini511/articles/722cb85067d4e9

問題無い例

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);

引用元

https://zenn.dev/akkie1030/articles/js-structured-clone

mapは新規に配列を作成するので元の配列に影響を与えないという先入観があり
ロクにコードを確認せずにテストしてみたら
妙な挙動をしたので調べてみたらこういうことだった。

記事を訂正
2024/11/02

Discussion

junerjuner

配列の中に配列がある入れ子状態だと、その配列の中の配列は参照渡しになってしまうので
新規に作成した配列の値を変更すると、元の値にも影響を及ぼす。

既存の配列インスタンスに対して破壊的操作を行った為では?参照渡しは変数への代入に対する話なので