JavaScript PR

JavaScriptのオブジェクトコピーを初心者向けに徹底解説!【シャローコピーとディープコピー】

記事内に商品プロモーションを含む場合があります

本記事では、
JavaScriptでオブジェクトコピーについて
初心者でも理解できるように、
これらのコピーの仕組みや実際にどう使うべきかをわかりやすく解説します。

JavaScriptでオブジェクトを扱う際に、
多くの人が最初に悩むのが「シャローコピー(浅いコピー)」と
「ディープコピー(深いコピー)」の違いですので
そのあたりもご説明します。

オブジェクトのコピーとは?

まずは、オブジェクトのコピーについて簡単に理解しましょう。

JavaScriptでは、データのコピーには大きく分けて2種類あります。

  1. プリミティブ型のコピー
    • これは、数値や文字列などのシンプルなデータ型です。この型の場合、変数に値をコピーすると、完全に独立した別の値が作られます。
  2. オブジェクト型のコピー
    • 一方、オブジェクトや配列のコピーは少し違います。これらをコピーすると、実際にはデータそのものをコピーするのではなく、**「参照」**と呼ばれるリンクをコピーします。つまり、コピー先とコピー元が同じデータを指してしまいます。

コピーの種類

シャローコピー(浅いコピー)

浅いコピーは、
オブジェクトの一層目(トップレベル)のみをコピーする方法です。

ネストされたオブジェクトや配列が含まれる場合、
内部のデータは参照としてコピーされ、
コピー先とコピー元が同じ内部データを指すことになります。

例えば、以下のようなコードを見てください。

let original = { name: "Alice", address: { city: "Tokyo" } };
let shallowCopy = Object.assign({}, original);

shallowCopy.name = "Bob"; // コピー先の名前を変更
console.log(original.name); // "Alice"(影響なし)

shallowCopy.address.city = "Osaka"; // コピー先の住所を変更
console.log(original.address.city); // "Osaka"(影響が出ている!)

ここでは、nameプロパティを
変更しても問題ありませんが、
addressオブジェクトを変更すると、
元のオブジェクトにも影響が出てしまいます。

ディープコピー(深いコピー)

一方、
ディープコピーはオブジェクト全体を、
深い階層まで完全にコピーします。

浅いコピーとは異なり、
ネストされたオブジェクトもすべて独立した
新しいオブジェクトとしてコピーされるため、
コピー元に影響を与えることがありません。

ディープコピーの方法の一つに、
JSON.stringify()JSON.parse()を使った方法があります。

let original = { name: "Alice", address: { city: "Tokyo" } };
let deepCopy = JSON.parse(JSON.stringify(original));

deepCopy.address.city = "Osaka"; // コピー先の住所を変更
console.log(original.address.city); // "Tokyo"(影響なし)

この方法を使えば、
コピー先の変更がコピー元に影響を与えないことが確認できます。

シャローコピーとディープコピーの具体的な実装方法

パターン1: Object.assign()によるシャローコピー

Object.assign()は、
オブジェクトを浅くコピーする方法です。
次のコード例を見てみましょう。

let original = { name: "Alice", age: 25 };
let shallowCopy = Object.assign({}, original);

この場合、originalオブジェクトの表層だけをコピーしますが、ネストされたオブジェクトや配列には注意が必要です。

パターン2: スプレッド構文によるシャローコピー

スプレッド構文も浅いコピーを実行します。

以下はその例です。

let original = { name: "Alice", age: 25 };
let shallowCopy = { ...original };

Object.assign()と同様に、
トップレベルのプロパティだけがコピーされますが、
内部にネストされたオブジェクトは同じ参照を持ちます。

パターン3: JSON.parse(JSON.stringify())によるディープコピー

ディープコピーの一つの簡単な方法として、
オブジェクトを一度JSON形式の文字列に変換し、
それを再びオブジェクトに変換する方法があります。

let deepCopy = JSON.parse(JSON.stringify(original));

ただし、この方法では、
undefinedや関数のプロパティは
コピーできないという制約があります。

パターン4: lodashcloneDeepによるディープコピー

外部ライブラリを使ったディープコピーの方法もあります。
lodashcloneDeep関数を使えば、より確実なディープコピーが可能です。

const _ = require('lodash');
let deepCopy = _.cloneDeep(original);

cloneDeepを使うことで、
すべてのプロパティが独立したコピーとして作成され、
内部にネストされたオブジェクトも正確にコピーされます。

パターン5: structuredCloneによるディープコピー

const original = { name: "Alice", age: 25 };
const deepCopy = structuredClone(original);
console.log(deepCopy);

関数、独自クラスのインスタンスや
Symbol あたりも対応はしていないようです。

コピーできるデータの詳細

ディープコピーの制約と注意点

ディープコピーにはいくつかの注意点があります。

例えば、プロトタイプチェーン上のプロパティや
アクセサプロパティ(getter/setter)はコピーされません。

また、コピー中に例外が発生すると、
コピーが中断されることもあります。
こうした点も覚えておきましょう。

まとめ

シャローコピーとディープコピーの違いを理解すると、JavaScriptでのオブジェクト操作が一層スムーズになります。浅いコピーはシンプルな場合に有効ですが、ネストされたオブジェクトや配列を安全にコピーしたい場合はディープコピーを使用することが推奨されます。

本記事では、
JavaScriptでオブジェクトをコピーする方法を紹介しました!
シャローコピーとディープコピーについての理解が深まり、
JavaScriptでのオブジェクトの扱いがより簡単になるはずです!

以上、誰かの参考になれば!

参考記事&関連情報