JavaScript 逆引き集 | オブジェクトのクローン(浅)

JavaScript JavaScript
スポンサーリンク

オブジェクトのクローン(浅)— スプレッド構文 {…obj} の基本と実践

浅いクローンは「一番上の層だけ」をコピーして、新しいオブジェクトを作る方法です。最短はスプレッド構文 {...obj}。ネストされたオブジェクトや配列は参照が共有される点だけ、しっかり掴んでおきましょう。


基本の使い方

const original = { name: "Aki", age: 22 };
const copy = { ...original };

copy.age = 23;
console.log(original.age); // 22(上位のプロパティは独立)
JavaScript
  • スプレッド構文: {...obj} で自身の列挙可能な「文字列キー」プロパティを上位層だけコピー。
  • ポイント: ネスト内(オブジェクト・配列など)は「同じ参照」を持つため、内側を変更すると元にも影響します。

ネストの落とし穴(参照が共有される)

const original = { profile: { city: "Tokyo" }, tags: ["js","web"] };
const copy = { ...original };

// 内側を変更すると両方に反映される
copy.profile.city = "Osaka";
copy.tags.push("frontend");

console.log(original.profile.city); // "Osaka"
console.log(original.tags);         // ["js","web","frontend"]
JavaScript
  • 理由: 浅いクローンは「上位のキー→参照」をコピー。参照先の中身は別クローンされない。

すぐ使えるテンプレート集

部分的に深くコピーする(ピンポイント対応)

const original = { user: { name: "Aki", addr: { city: "Tokyo" } } };

// userまでは浅コピー、addrは手動で浅コピーして“段階的に”参照切り離し
const copy = {
  ...original,
  user: {
    ...original.user,
    addr: { ...original.user.addr },
  },
};

copy.user.addr.city = "Osaka";
console.log(original.user.addr.city); // "Tokyo"(ここは分離できた)
JavaScript
  • ポイント: 必要な深さまで段階的に {...} を噛ませて参照を切る。

配列を含むオブジェクトを浅クローン

const original = { list: [1,2,3] };
const copy = { ...original, list: [...original.list] }; // 配列は別途スプレッド
copy.list[0] = 9;
console.log(original.list[0]); // 1
JavaScript
  • ポイント: 配列の分離は [...]。オブジェクトの分離は {...}

Object.assign でも同じ(浅コピー)

const original = { a: 1, b: { c: 2 } };
const copy = Object.assign({}, original);
copy.b.c = 3;
console.log(original.b.c); // 3(ネストは共有)
JavaScript
  • ポイント: スプレッドと assign は同じ“浅い”挙動。お好みで。

よくある型別の注意点

  • 関数・Date・Map/Set: 浅コピーでは「参照がそのまま」。Dateは同じインスタンス、Map/Setも同じコレクションを指す。
  • Symbolキー: スプレッドは列挙可能な Symbol もコピーされますが、存在や列挙設定に注意。
  • 非列挙プロパティ: enumerable: false なプロパティはスプレッドではコピーされません(必要なら defineProperty で手動移植)。

深いクローンが必要なとき(参考)

  • 簡易:JSON.parse(JSON.stringify(obj))
    • 注意: 関数/undefined/Symbol/Date/Map/Set/BigIntなどは失われる、循環参照で失敗。
  • 推奨:structuredClone(obj)(ブラウザ/Nodeの新しめ環境)
    • 特徴: 多くの型に対応し、循環参照もOK。Map/Set/Date/ArrayBufferなどを安全に複製。
  • ライブラリ: ルール込みの深いクローンが必要なら専用ライブラリを検討。

実務での使い分け指針

  • UI状態の更新(部分的に参照を切る): 必要な階層にだけ {...}[...] を差し込む。
  • データ加工のワンショット: 浅コピーで十分なら {...obj}。ネストの変更が元を汚さないよう、適宜“段階的スプレッド”。
  • 厳密な複製が必要: structuredClone。JSON法は「純粋なデータのみ」の場面に限定。

練習問題(手を動かして覚える)

  • 1. 浅クローンでネストが共有されることを確認
const o = { inner: { x: 1 } };
const c = { ...o };
c.inner.x = 9;
console.log(o.inner.x); // 9
JavaScript
  • 2. 段階的スプレッドで参照を切る
const o = { a: { b: { c: 1 } } };
const c = { ...o, a: { ...o.a, b: { ...o.a.b } } };
c.a.b.c = 7;
console.log(o.a.b.c); // 1
JavaScript
  • 3. 配列を別コピーして安全に編集
const o = { arr: [1,2,3] };
const c = { ...o, arr: [...o.arr] };
c.arr.push(4);
console.log(o.arr.length); // 3
JavaScript

直感的な指針

  • 上位だけ複製、内側は共有: 浅クローンの本質。
  • 必要な階層だけ分離: 段階的に {...}[...] を入れる。
  • 深い複製が必要なら: structuredClone を優先。JSON法は型が失われるので用途限定。
タイトルとURLをコピーしました