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 つの解決策 (要約)

推薦する

シンプルなドラッグ効果を実現するjs

この記事では、簡単なドラッグ効果を実現するためのjsの具体的なコードを参考までに共有します。具体的な...

Nginx プロキシを使用してインターネットを閲覧する方法

私は通常、Tomcatや他のアプリケーションのリバースプロキシとしてnginxを使用しています。実際...

Ubuntu 18.04 でソースコードから Odoo14 をインストールするチュートリアル

目次このシリーズの背景概要PostgreSQL データベースの準備ソースからインストール仮想環境の作...

Vue は検証コードのカウントダウンボタンを実装します

この記事では、検証コードカウントダウンボタンを実装するためのVueの具体的なコードを例として紹介しま...

JS 関数とコンストラクタを簡単に理解する

目次1. 概要1.1 Functionコンストラクタを使用して関数を作成する1.2 機能と目的2. ...

CSS アニメーション プロパティの使用方法とサンプル コード (transition/transform/animation)

開発中、優れたユーザー インターフェイスには常にいくつかのアニメーションが組み込まれます。 CSS ...

基本的なウェブページパフォーマンス最適化ルールの簡単な概要

ブラウザのウェブページを最適化するためのいくつかのルールページの最適化静的リソース圧縮ビルド ツール...

MySQL におけるデータベース間関連クエリメソッド

ビジネスシナリオ: 異なるデータベース内のテーブルをクエリするたとえば、関連付けられるテーブルは、マ...

Linux システムでの CPU 使用率が高い場合のトラブルシューティングのアイデアと解決策

序文Linux 運用保守エンジニアとして、日々の業務の中で Linux サーバーの CPU 負荷が ...

CSSインジェクションの知識の要約

最近のブラウザでは、CSS 内で JavaScript を実行することはできなくなりました。以前は、...

下線を実現するための CSS3 トランジションの例コード

この記事では、下線を実現するための CSS3 トランジションのサンプル コードを紹介します。このコー...

Vue+Router+Element でシンプルなナビゲーションバーを実装する

このプロジェクトでは、Vue+Router+Element の具体的なコードを共有して、シンプルなナ...

CSS が初期読み込み時の白い画面の時間に与える影響

外部 CSS ファイルを使用したレンダリング パイプライン上図では、HTML データの要求から DO...

ウェブページ内でウェブテーブルやdivレイヤーが引き伸ばされる問題の解決策

<br />Web ページをデザインするときには、いつも不快なことに遭遇します。最も一般...

Linux環境でタイムゾーンを設定できない問題を解決

Linuxでタイムゾーンを変更する場合、常に変更することはできませんAsia/Shanghai に変...