JavaScript
 Computer >> コンピューター >  >> プログラミング >> JavaScript

JavaScriptのシャローコピーとディープコピーの違いを徹底解説

シャローコピー(浅いコピー)とディープコピー(深いコピー)という概念は、JavaScriptに限らず多くのプログラミング言語に共通するものです。オブジェクトを扱う上でこの違いを正しく理解することは、予期しないバグを防ぐために非常に重要です。

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

シャローコピーは、必要最小限の範囲だけを複製する方法です。コレクション(オブジェクトや配列)のコピーを作成する場合、複製されるのはあくまで「構造」だけであり、その中に格納された要素(ネストされたオブジェクトなど)までは複製されません。そのため、元のオブジェクトとコピー先のオブジェクトは、内部の要素を共有することになります。

つまり、トップレベルのプロパティのみが新しく作られ、ネストされたオブジェクトへの参照はそのまま引き継がれるのです。

シャローコピーのコード例

let innerObj = {
    a: 'b',
    c: 'd'
}
let obj = {
    x: "test",
    y: innerObj
}
// シャローコピーを作成
let copyObj = Object.assign({}, obj);
// copyObj と obj のプロパティ y は同じ innerObj を参照しているため、
// 変更は両方に反映される
innerObj.a = "test"
console.log(obj)
console.log(copyObj)

実行結果

{ x: 'test', y: { a: 'test', c: 'd' } }
{ x: 'test', y: { a: 'test', c: 'd' } }

この例では、Object.assign() を使ってシャローコピーを作成しています。innerObj.a の値を変更すると、元の obj とコピー先の copyObj の両方に出力が反映されています。これは両者が同一の innerObj を参照しているためです。

注意点: シャローコピーは再帰的にクローンを作成しません。コピーが行われるのは最上位の階層(トップレベル)のみです。

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

ディープコピーは、すべてを完全に複製する方法です。コレクションのディープコピーを行うと、元のコレクションに含まれる全要素が再帰的にクローンされた、まったく独立した2つのコレクションが生成されます。そのため、コピー後に元のオブジェクトを変更しても、コピー先には一切影響しません。

ディープコピーのコード例

let innerObj = {
    a: 'b',
    c: 'd'
}
let obj = {
    x: "test",
    y: innerObj
}
// ディープコピーを作成
let copyObj = JSON.parse(JSON.stringify(obj))
// copyObj は独立したコピーなので、innerObj を変更しても影響しない
innerObj.a = "test"
console.log(obj)
console.log(copyObj)

実行結果

{ x: 'test', y: { a: 'test', c: 'd' } }
{ x: 'test', y: { a: 'b', c: 'd' } }

この例では、JSON.stringify() で文字列化してから JSON.parse() でパースするという手法でディープコピーを作成しています。実行結果を見ると、innerObj.a を変更後も copyObj の値は 'b' のまま維持されており、完全に独立したコピーが作られていることがわかります。

補足:モダンなディープコピーの方法

JSON.parse(JSON.stringify()) という手法は手軽ですが、undefined、関数、SymbolDate オブジェクトなどが正しく复制されないという制限があります。近年のJavaScript環境(Node.js 17以降、主要ブラウザ)では、より安全で正確な structuredClone() メソッドが利用可能です。

let copyObj = structuredClone(obj);

用途や対応環境に応じて、これらの方法を使い分けることをおすすめします。

まとめ

  • シャローコピー: トップレベルの構造のみをコピーし、ネストされたオブジェクトは参照を共有する(例:Object.assign()、スプレッド構文 {...obj}
  • ディープコピー: ネストされた要素まで再帰的に完全に複製し、互いに独立したコピーを作る(例:JSON.parse(JSON.stringify())structuredClone()
  1. JavaScriptで配列の合計と積の絶対差を求める方法

    本記事では、数値の配列を唯一の引数として受け取り、配列内のすべての数値の合計と積を計算し、その絶対差を返すJavaScript関数の実装方法を解説します。例えば、配列 [1, 4, 1, 2, 1, 6, 3] の場合、合計は 18、積は 144 となるため、返される値は |18 − 144| = 126 になります。実装コード以下がそのコード例です −const arr = [1, 4, 1, 2, 1, 6, 3]; const sumProductDifference = (arr = []) => {     const creds = a

  2. PHPとJavaScriptの違いとは?特徴・実行環境・使い分けを徹底解説

    はじめに 本記事では、Web開発で広く使われる2つのプログラミング言語——PHPとJavaScriptの主な違いについて詳しく解説します。それぞれの特徴や動作環境を理解することで、プロジェクトに応じた適切な言語選択ができるようになります。 JavaScriptの特徴 フロントエンドとバックエンドの両方を担当可能:ブラウザ上のUI制御から、Node.jsを使ったサーバーサイド処理まで幅広く対応できます。 非同期処理に対応:入出力操作の完了を待たずに次の処理へ進むため、レスポンスの速いアプリケーションを構築できます。 実行環境が柔軟:ブラウザで直接実行できるほか、「Node.js」の登場以降は