【Angular】配列やオブジェクトのコピーの注意点 - ChuN6868/CodeChrysalis-fullstuck-project GitHub Wiki

🧠 配列コピーと参照の違いまとめ

✅ 比較対象

番号 コピー方法 内容
同じ配列を共有している場合 arr1 = arr2
スプレッド構文による浅いコピー arr2 = [...arr1]
スプレッド+mapによる1階層の深いコピー arr2 = arr1.map(item => ({ ...item }))

📋 各パターンの比較

項目 ① 同じ配列を共有 ② スプレッド構文(浅いコピー) ③ map+スプレッド(1階層の深いコピー)
配列自体は別になる? ❌ いいえ ✅ はい ✅ はい
中のオブジェクトも別? ❌ いいえ ❌ いいえ ✅ はい
片方を変更すると他方は? ✅ 影響あり ✅ 影響あり ❌ 影響なし
安全性 ❌ 危険 ⚠️ 注意 ✅ 安全
主な用途 同期処理・テスト 並び替え・一時処理など 安全なコピーが必要なとき

💡 実例コード

① 同じ配列を共有している場合

const shared = [{ name: 'Alice' }];
const arr1 = shared;
const arr2 = shared;

arr2[0].name = 'Bob';
console.log(arr1[0].name); // "Bob" ← arr1 も変わる

② スプレッド構文(浅いコピー)

const arr1 = [{ name: 'Alice' }];
const arr2 = [...arr1];

arr2[0].name = 'Bob';
console.log(arr1[0].name); // "Bob" ← 中のオブジェクトは共有されている

③ map+スプレッド構文(1階層ディープコピー)

const arr1 = [{ name: 'Alice' }];
const arr2 = arr1.map(item => ({ ...item }));

arr2[0].name = 'Bob';
console.log(arr1[0].name); // "Alice" ← 元のデータは変わらない

🧭 ネストが深い場合のコピー方法(参考)

structuredClone()(ブラウザ対応)

const deepCopy = structuredClone(arr1);

lodash.cloneDeep()(ライブラリ)

import cloneDeep from 'lodash/cloneDeep';
const deepCopy = cloneDeep(arr1);

🌍 他言語でも同じことが当てはまる?

✅ 同じ参照の問題が起こる代表的な言語

言語 内容・コメント
✅ JavaScript TypeScript と同じ。配列・オブジェクトは参照型
✅ Python list, dict は参照型。copy()deepcopy() が必要
✅ Java ArrayList, Map などは参照型。clone()new コピーが必要
✅ C# class は参照型、List<T>.ToList() でコピーできる
✅ Ruby Array, Hash は参照型。.dup, .clone でコピー
✅ PHP 配列はコピーされるが参照渡しも可能。clone でオブジェクト複製
✅ Swift class は参照型、struct は値型でコピーされる

❌ 適用されにくい(ただし似た問題は起こる)

言語 コメント
❌ C/C++ 値型中心だが、ポインタを使えば同様の参照問題が起きる
❌ Go 配列は基本的に値渡し。slicemap で似た問題が発生することあり

✅ まとめ:選び方の目安

目的 推奨コピー方法
同じデータをそのまま共有したい arr1 = arr2
配列構造だけコピーしたい(中身共有OK) arr2 = [...arr1]
中のオブジェクトも完全に独立させたい arr2 = arr1.map(item => ({ ...item }))
ネストされた構造も全部独立させたい structuredClone() または cloneDeep()