Deep vs Shallow Copy: JSON.parse と stringify の落とし穴
2025-03-19
元データを壊さずに編集したいとき、JSON の往復は手軽です。ただし純粋な JSON 以外の値が混ざると、値消失や例外がすぐ発生します。
Shallow copy と deep copy
スプレッドや Object.assign は 1 階層のみ複製し、ネストは共有参照のままです。
JSON 往復は JSON で表現できる値だけを保持します。
何が失われるか
undefined、関数、Symbol キーは落ち、Date は文字列になります。
Map/Set/RegExp は期待通り残らず、NaN/Infinity も問題を起こします。
const o = { d: new Date(), fn: () => 1, u: undefined };
JSON.parse(JSON.stringify(o)); // { d: "2026-06-10T..." }循環参照は例外
obj.self = obj のような構造は Converting circular structure to JSON を発生させます。
グラフ構造は JSON ではなく structuredClone や WeakMap 走査を使います。
structuredClone が有利な場面
モダンブラウザと Node 17+ で Date/Map/Set/循環参照を保持できます。
関数や DOM ノード、独自プロトタイプの振る舞いは維持されません。
使い分けの指針
API レスポンスのような純 JSON には JSON 往復が軽量です。
Date や循環参照を含む場合は structuredClone、複雑なクラス構造は cloneDeep を検討します。