本記事では、
JavaScriptでオブジェクトコピーについて
初心者でも理解できるように、
これらのコピーの仕組みや実際にどう使うべきかをわかりやすく解説します。
JavaScriptでオブジェクトを扱う際に、
多くの人が最初に悩むのが「シャローコピー(浅いコピー)」と
「ディープコピー(深いコピー)」の違いですので
そのあたりもご説明します。
オブジェクトのコピーとは?
まずは、オブジェクトのコピーについて簡単に理解しましょう。
JavaScriptでは、データのコピーには大きく分けて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: lodash
のcloneDeep
によるディープコピー
外部ライブラリを使ったディープコピーの方法もあります。lodash
のcloneDeep
関数を使えば、より確実なディープコピーが可能です。
const _ = require('lodash');
let deepCopy = _.cloneDeep(original);
cloneDeep
を使うことで、
すべてのプロパティが独立したコピーとして作成され、
内部にネストされたオブジェクトも正確にコピーされます。
パターン5: structuredCloneによるディープコピー
const original = { name: "Alice", age: 25 };
const deepCopy = structuredClone(original);
console.log(deepCopy);
ディープコピーの制約と注意点
ディープコピーにはいくつかの注意点があります。
例えば、プロトタイプチェーン上のプロパティや
アクセサプロパティ(getter/setter)はコピーされません。
また、コピー中に例外が発生すると、
コピーが中断されることもあります。
こうした点も覚えておきましょう。
まとめ
シャローコピーとディープコピーの違いを理解すると、JavaScriptでのオブジェクト操作が一層スムーズになります。浅いコピーはシンプルな場合に有効ですが、ネストされたオブジェクトや配列を安全にコピーしたい場合はディープコピーを使用することが推奨されます。
本記事では、
JavaScriptでオブジェクトをコピーする方法を紹介しました!
シャローコピーとディープコピーについての理解が深まり、
JavaScriptでのオブジェクトの扱いがより簡単になるはずです!
以上、誰かの参考になれば!