JavaScriptの浅いコピーと深いコピーについての簡単な説明

JavaScriptの浅いコピーと深いコピーについての簡単な説明

このトピックについては、インターネット上で多くの議論が行われています。私はさまざまな状況に応じて自分でそれらを整理しました。最終的には、ディープ コピーをほぼ完璧に実現することができました。皆さんの議論をお待ちしています。

javascriptのオブジェクトは参照型です。オブジェクトをコピーするときは、浅いコピーを使用するか深いコピーを使用するかを検討する必要があります。

1. 直接譲渡

オブジェクトは参照型です。別のオブジェクトに直接割り当てられている場合は、単なる参照です。実際、2 つの変数は同じデータ オブジェクトを指します。1 つのオブジェクトのプロパティが変更されると、もう 1 つのオブジェクトのプロパティも変更されます。

例1、簡単な例:

人間1 = {
    id: 1,
    名前: 「ハッピー」
};
human2 = human1; // ここでは直接代入です console.log(human1); // {id: 1, name: 'happy'}
console.log(human2); // {id: 1, name: 'happy'}
 
// human1 の名前を変更すると human2 の名前も変更されます。human1.name = "life";
console.log(human1); // {id: 1, 名前: 'life'}
console.log(human2); // {id: 1, 名前: 'life'}

例 2: オブジェクトをパラメータとして渡すと参照も渡されます。

人間1 = {
    id: 1,
    名前: 「ハッピー」
};
 
console.log(human1); // {id: 1, name: 'happy'}
 
関数 foo(人間) {
    // ここで人間オブジェクトの名前が変更されます human.name = "life";
}
foo(human1); // オブジェクトは参照渡しです console.log(human1); // {id: 1, name: 'life'}

2. 浅いコピー

浅いコピーでは、オブジェクトの最初のレイヤーのみがコピーされます。最初のレイヤーのプロパティ値がオブジェクトの場合、プロパティへの参照のみがコピーされます。

オブジェクト1 = {
    a: 1、
    b: { // bはオブジェクト b1: 2
    }
};
object2 = Object.assign({}, object1); // これは浅いコピーであり、オブジェクト b の参照のみがコピーされます // a は通常の型であり、互いに影響しません object1.a = 10;
コンソール.log(オブジェクト1.a); // 10
コンソール.log(object2.a); // 1
 
// b は相互に影響を与えるオブジェクトです。object1.b.b1 = 20;
コンソール.log(object1.b.b1); // 20
コンソール.log(object2.b.b1); // 20


完全なコピーを実現するには、ディープ コピーを使用する必要があります。

3. ディープコピー

Sen コピーとは、1 つのレイヤーをコピーするだけでなく、その内部のレイヤー (オブジェクトの場合) もコピーする必要があることを意味します。

1. JSONオブジェクトメソッド

オブジェクトがJSONオブジェクトであることが確認できる場合は、 JSONオブジェクト形式で使用できます。

上記の例を使用します。

オブジェクト1 = {
    a: 1、
    b: { // bはオブジェクト b1: 2
    }
};
 
object2 = JSON.parse(JSON.stringify(object1)); // ディープコピー // a は通常の型なので互いに影響しません。object1.a = 10;
コンソール.log(オブジェクト1.a); // 10
コンソール.log(object2.a); // 1
 
// b はオブジェクトなので互いに影響しません object1.b.b1 = 20;
コンソール.log(object1.b.b1); // 20
コンソール.log(object2.b.b1); // 2


ここでのディープ コピーの原理は、実際にはオブジェクトを最初にjson文字列に変換し、次にjsonオブジェクトに変換することです。JSON json列に変換された後は、元のオブジェクトとは何の関係もありません。

この方法の利点:実装が非常に簡単です。

欠点:

属性値が関数である場合、コピーできず、データが失われます。
また、プロトタイプ オブジェクトはコピーできません。

したがって、このメソッドは純粋なjsonデータであることが確認されたオブジェクトにのみ適しています。

2. 再帰コピー

レイヤーごとにコピーする必要があるため、再帰的なアプローチを使用することは簡単です。次の実装を参照してください。

関数 deepCopy(ソース) {
    // オブジェクトまたは null でない場合は直接返します if (typeof source !== 'object' || source === null) {
        ソースを返します。
    }
 
    ターゲットを{}とします。
    // プロパティをトラバースしてコピーする for (let k in source) {
        if (!source.hasOwnProperty(k)) {
            続く;
        }
 
        if (typeof source[k] === 'object') { // オブジェクトの場合は再帰的にコピーします target[k] = deepCopy(source[k]);
            続く;
        }
 
        記述子を Object.getOwnPropertyDescriptor(source, k); とします。
        Object.defineProperty(ターゲット、k、記述子);
    }
 
    ターゲットを返します。
}

オブジェクトはレイヤーごとにコピーされるため、コピーが完了した後、2 つのオブジェクトは互いに影響を与えず、メソッドもサポートされます。

オブジェクト1 = {
    a: 1、
    b: { // bはオブジェクト b1: 2
    },
    f: function() { // f はメソッドです console.log(3);
    }
};
object2 = deepCopy(object1); // ディープコピー。関数もコピーできます。
オブジェクト1.f(); // 3
オブジェクト2.f(); // 3
 
// b はオブジェクトなので互いに影響しません object1.b.b1 = 20;
コンソール.log(object1.b.b1); // 20
コンソール.log(object2.b.b1); // 2


プロトタイプオブジェクトのコピー

しかし、この方法にはまだ問題があります。つまり、プロトタイプ オブジェクトをコピーできないのです。これを少し改善してみましょう。

// プロトタイプもコピーされるように、let target = {}; を次のように変更します。let target = Object.create(Object.getPrototypeOf(source));


以上です。例を使って確認してみましょう。

関数Human() {
    id = 1;
}
Human.prototype.bar = 関数() {
    console.log("バー");
};
 
human1 を新しい Human() にします。
人間2 = deepCopy(人間1);
 
console.log("人間1", 人間1);
console.log("human2", human2);


次の 2 つのオブジェクトのプロトタイプを見てみましょう。

プロトタイプ オブジェクトをディープ コピーします。

完璧なコピーです。

もちろん、この方法には問題があります。再帰レベルが深すぎると、スタックオーバーフローが発生しやすくなります。ただし、実際には、非常に大きなオブジェクトをコピーしないことも推奨されます。他の適切な解決策があるはずです。

JavaScriptシャローコピーとディープコピーに関するこの記事はこれで終わりです。JavaScript JavaScriptシャローコピーとディープコピーに関するより関連性の高いコンテンツについては、123WORDPRESS.COM の過去の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

参考資料:

JS はディープコピーを実装します: https://www.cnblogs.com/dobeco/p/11295316.html
Object.assign(): https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
Object.create(): https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/create
Object.getPrototypeOf(): https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/getPrototypeOf
Object.defineProperty(): https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
Object.getOwnPropertyDescriptor(): https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptor
hasOwnProperty(): https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty

以下もご興味があるかもしれません:
  • JavaScript のディープコピーとシャローコピーの詳しい説明
  • js における浅いコピーと深いコピーの詳細な説明
  • JS変数ストレージのディープコピーとシャローコピーの詳しい説明
  • JS オブジェクトのコピー (ディープ コピーとシャロー コピー)
  • JavaScriptのディープコピーとシャローコピーに関するよくある話

<<:  MySQL infobrightのインストール手順

>>:  クロスブラウザの問題に対する 5 つの解決策 (要約)

推薦する

HTMLはa要素hrefのURLリンクを自動的に更新したり新しいウィンドウを開いたりする機能を実装する

場合によっては、次のような機能を実装したいことがあります。リンクをクリックします。リンクがブラウザで...

Windows Server 2016 に MySQL 5.7.19 の解凍バージョンをインストールするための詳細なチュートリアル

MySQL 5.7.19 winx64 解凍版のインストールチュートリアルを収録しています。具体的な...

CSS スタイルを使用して表のフォントを垂直中央に配置する方法

CSS スタイルを使用して表内のフォントを垂直方向に中央揃えする方法は次のとおりです。下図のようなカ...

フォーム送信ページの更新がジャンプしない

1. ソースコードの設計コードをコピーコードは次のとおりです。 <!DOCTYPE html ...

MySQL テーブルを削除する際の I/O エラーの原因分析と解決方法

問題現象最近、sysbench を使用して MySQL をテストしました。テストに長い時間がかかった...

IE6では画像要素imgに余分な空白スペースがある

ページの DIV+CSS レイアウトを行う際、IE6 で画像要素 img の下に余分なスペースができ...

2級コンピュータ試験のMySQL知識ポイント mysql alterコマンド

テーブル構造を編集するための MySQL の alter コマンドの使用。具体的な内容は以下のとおり...

Windows で mysql-8.0.18-winx64 をインストールするチュートリアル (画像とテキスト付き)

1. インストールパッケージをダウンロードするインストール パッケージは次の場所にあります:参考:...

MySqlエスケープの詳細な使用例

MySQL エスケープエスケープとは、エスケープ文字の本来の意味を意味します。エスケープ文字の目的は...

jquery-multiselect を使用した IE6 のバグの解決方法

jquery-multiselect (ドロップダウン ボックスをチェックボックス付きの複数選択コン...

Linuxにおけるumaskコマンドの使用原理と計算方法の詳しい解説

目次umask umaskの使用法原理1. umask値2. ファイルディレクトリの最大権限3. 従...

スクリプトを使用して、ワンクリックでDockerイメージをパッケージ化してアップロードします。

著者は1年以上マイクロフロントエンドプロジェクトに取り組んできました。チームは10個のマイクロアプリ...

非常に実用的なMySQL関数の包括的な概要、詳細な例の分析チュートリアル

目次1. MySQLの関数の説明2. 単行関数の分類3. キャラクター機能4. 数学関数5. 日付と...

three.js を使って立体的な矢印線を描く詳細な手順

需要: この需要は緊急に必要です!地下鉄のシーンでは、脱出経路を示す矢印を描かなければなりません。こ...