ホームページ >ウェブフロントエンド >jsチュートリアル >JavaScriptの浅いコピーとディープコピー

JavaScriptの浅いコピーとディープコピー

Jennifer Aniston
Jennifer Anistonオリジナル
2025-02-09 08:28:10901ブラウズ

Shallow vs. Deep Copying in JavaScript

JavaScriptオブジェクトをコピーすることは、見かけほど単純ではありません。このプロセス中にオブジェクトと参照がどのように機能するかを理解することは、Web開発者にとって重要であり、デバッグ時間の時間を節約できます。これは、ReactやVueに組み込まれたものなど、大規模なステートフルアプリケーションを使用するとますます重要になります。

浅いコピーとディープコピーは、JavaScriptでオブジェクトのコピーを作成する方法と、「コピー」で作成するデータを参照してください。この記事では、これらの方法の違いを深く掘り下げ、それらの実用的なアプリケーションを調査し、それらを使用するときに生じる可能性のある潜在的な落とし穴を明らかにします。

キーポイント

JavaScriptの浅いコピーは、既存のオブジェクトのプロパティをコピーするが、元の値またはオブジェクトへの同じ参照を保持する新しいオブジェクトを作成します。これは、浅いレプリカのネストされたオブジェクトの変更も、元のオブジェクトや他の浅いレプリカに影響することを意味します。
    一方、ディープコピーは、単なる参照ではなく、そのすべてのプロパティとネストされたオブジェクトを含む既存のオブジェクトの正確なコピーを作成します。これにより、参照を共有しない2つの個別のオブジェクトが必要な場合、深いコピーが有益になり、1つのオブジェクトへの変更が他のオブジェクトに影響を与えないようにします。
  • ディープレプリケーションはデータの精度の利点を提供しますが、パフォーマンスへの影響、メモリ消費の増加、円形の参照の問題、機能と特別なオブジェクトの処理、実装の複雑さなどのいくつかの欠点もある場合があります。したがって、特定のユースケースごとに深い複製が必要かどうかを評価することが重要です。
  • 「浅い」コピー
  • とは何ですか
浅いコピーとは、新しいオブジェクトを作成するプロセスを指します。これは、プロパティが元のオブジェクトと同じ数値値またはオブジェクトを参照する既存のオブジェクトのコピーです。 JavaScriptでは、これは通常、

または拡張構文(

)などのメソッドを使用して達成されます。浅いコピーは、既存のオブジェクトまたは値への新しい参照のみを作成し、深いコピーを作成しません。つまり、ネストされたオブジェクトはまだ参照されており、複製ではありません。

Object.assign()次のコードの例を見てみましょう。新しく作成されたオブジェクトは、オペレーターを拡張することによって作成された{...originalObject}のコピーです。これには、予想外の結果があります。

shallowCopyZooしかし、zooに正確に何があるか見てみましょう。プロパティ

および
<code class="language-javascript">let zoo = {
  name: "Amazing Zoo",
  location: "Melbourne, Australia",
  animals: [
    {
      species: "Lion",
      favoriteTreat: "?",
    },
    {
      species: "Panda",
      favoriteTreat: "?",
    },
  ],
};

let shallowCopyZoo = { ...zoo };
shallowCopyZoo.animals[0].favoriteTreat = "?";
console.log(zoo.animals[0].favoriteTreat); 
// "?",而不是 "?"</code>
は元の値(文字列)であるため、値がコピーされます。ただし、

プロパティはオブジェクトの配列であるため、コピーされるのは、配列自体ではなく、その配列への参照です。 shallowCopyZoo nameStrict Equality Operator()を使用して、これをすばやくテストできます(私を信じていない場合)。オブジェクトが同じオブジェクトを参照する場合にのみ、1つのオブジェクトは別のオブジェクトに等しくなります(プリミティブデータ型と参照データ型を参照)。 location属性は両方で等しいが、オブジェクト自体は等しくないことに注意してください。 animals

<code class="language-javascript">let zoo = {
  name: "Amazing Zoo",
  location: "Melbourne, Australia",
  animals: [
    {
      species: "Lion",
      favoriteTreat: "?",
    },
    {
      species: "Panda",
      favoriteTreat: "?",
    },
  ],
};

let shallowCopyZoo = { ...zoo };
shallowCopyZoo.animals[0].favoriteTreat = "?";
console.log(zoo.animals[0].favoriteTreat); 
// "?",而不是 "?"</code>

これは、コードベースに潜在的な問題を引き起こす可能性があり、大規模な変更に対処する場合に特に困難です。浅いレプリカでネストされたオブジェクトを変更すると、すべてが同じ参照を共有するため、元のオブジェクトやその他の浅いレプリカにも影響します。

ディープコピー

ディープコピーは、既存のオブジェクトの正確なコピーである新しいオブジェクトを作成するためのトリックです。これには、参照ではなく、すべてのプロパティとネストされたオブジェクトをコピーすることが含まれます。ディープクローニングは、参照を共有しない2つの個別のオブジェクトが必要な場合に役立ち、1つのオブジェクトへの変更が他のオブジェクトに影響を与えないようにします。

プログラマーは、複雑なアプリケーションでアプリケーション状態オブジェクトを扱うときに、多くの場合、深いクローニングを使用します。以前の状態に影響を与えることなく新しい状態オブジェクトを作成することは、アプリケーションの安定性を維持し、元に戻す/redo機能を正しく実装するために重要です。

ディープコピーに

およびJSON.stringify()を使用する方法JSON.parse()

人気のあるライブラリフリーのディープコピー方法は、組み込み

およびJSON.stringify()メソッドを使用することです。 JSON.parse()

メソッドは完璧ではありません。たとえば、parse(stringify())などの特別なデータ型は文字列に変換され、未定義の値は無視されます。この記事のすべてのオプションと同様に、特定のユースケースに基づいてそれを考慮する必要があります。 Date

次のコードでは、これらのメソッドを使用して

関数を作成して、オブジェクトを深くクローン化します。次に、元のオブジェクトに影響を与えることなく、deepCopyオブジェクトをコピーしてコピーしたオブジェクトを変更します。これは、参照を共有しない独立したオブジェクトを維持する際の深い複製の価値を示しています。 playerProfile

深い複製のためのライブラリ
<code class="language-javascript">console.log(zoo.animals === shallowCopyZoo.animals)
// true

console.log(zoo === shallowCopyZoo)
// false</code>

深い複製ソリューションを提供するさまざまなサードパーティライブラリもあります。

Lodash Libraryの
    関数は、ループ参照、機能、および特別なオブジェクトを正しく処理できます。
  • JQuery Libraryの関数cloneDeep()
  • extend()Immerライブラリは、React-Redux開発者向けに構築されており、オブジェクトを変更するための便利なツールを提供します。 [deep = true]
  • バニラJSディープコピー関数
  • 何らかの理由でJSONオブジェクトやサードパーティライブラリを使用したくない場合は、Vanilla JavaScriptにカスタムディープコピー機能を作成することもできます。この関数は、オブジェクトのプロパティを再帰的に反復し、同じプロパティと値を持つ新しいオブジェクトを作成します。

ディープコピーの欠点

深い複製はデータの精度に大きな利点をもたらしますが、特定のユースケースごとに深い複製が必要かどうかを評価することをお勧めします。場合によっては、オブジェクト参照を管理するための浅いコピーまたはその他の手法がより適切である可能性があり、それによりパフォーマンスが向上し、複雑さが低下します。

  1. パフォーマンスの影響:特に大型または複雑なオブジェクトを扱う場合、深い複製は計算上高価です。深い複製プロセスは、すべてのネストされたプロパティを反復するため、アプリケーションのパフォーマンスに悪影響を与えるには多くの時間がかかる場合があります。
  2. メモリ消費:ディープコピーの作成は、すべてのネストされたオブジェクトを含むオブジェクト階層全体で結果をもたらします。これにより、メモリ使用量が増加する可能性があり、メモリが制約された環境や大規模なデータセットを処理するときに問題になる可能性があります。
  3. ラウンドリファレンス:ディープコピーは、オブジェクトに円形の参照が含まれている場合(つまり、オブジェクトのプロパティが直接または間接的にそれ自体を参照する場合)に問題を引き起こす可能性があります。ループ参照は、ディープコピー中に無限のループまたはスタックオーバーフローエラーを引き起こす可能性があり、それらを処理するには、これらの問題を回避するために追加のロジックが必要です。
  4. 関数と特別なオブジェクトの処理:ディープコピーは、予想どおりに特別な特性を持つ関数またはオブジェクトを処理できない場合があります(たとえば、DateRegExp、DOM要素)。たとえば、関数を含むオブジェクトを深くコピーする場合、関数への参照がコピーされる場合がありますが、関数の閉鎖とその結合コンテキストはコピーされません。同様に、特別な機能を備えたオブジェクトは、深く複製すると一意の特性と動作を失う可能性があります。
  5. 実装の複雑さ:カスタムディープコピー関数の作成は複雑になる可能性があり、JSON.parse(JSON.stringify(obj))のような組み込みのメソッドには、関数を正しく処理できない、円形参照、または特別なオブジェクトなどの制限もあります。ディープレプリケーションをより効率的に処理するLodashのようなサードパーティライブラリがいくつかありますが、深い複製のために外部依存関係を追加することは必ずしも理想的ではないかもしれません。 _.cloneDeep()
結論

この記事を読んでくれてありがとう。浅くて深い複製は、初心者が考えるよりもはるかに複雑です。各アプローチには多くの落とし穴がありますが、これらのオプションを確認して検討するために時間をかけて、アプリケーションとデータがあなたがどのように見えるかを保証することを保証します。

JavaScript(FAQ)

の浅い複製と深い複製に関する FAQ

JavaScriptの浅い複製と深い複製の主な違いは何ですか?

浅い複製と深い複製の主な違いは、オブジェクトとしてプロパティを処理する方法です。浅いコピーでは、コピーされたオブジェクトは、元のオブジェクトと同じ参照をネストされたオブジェクトと共有します。これは、ネストされたオブジェクトの変更が元のオブジェクトとコピーオブジェクトに反映されることを意味します。一方、ディープレプリケーションは、ネストされたオブジェクトの新しいインスタンスを作成します。つまり、複製されたオブジェクト内のネストされたオブジェクトの変更は、元のオブジェクトに影響しません。

拡張演算子は浅いコピーでどのように機能しますか?

JavaScriptの拡張演算子(…)は通常、浅いコピーに使用されます。あるオブジェクトのすべての列挙可能なプロパティを別のオブジェクトにコピーします。ただし、ネストされたオブジェクトへの最初のレベルの属性と参照のみをコピーします。したがって、ネストされたオブジェクトの変更は、元のオブジェクトとコピーされたオブジェクトに影響します。

深いコピーにJSONメソッドを使用できますか?

はい、JSONメソッドを使用して、JavaScriptでディープコピーを実行できます。 JSON.stringify()JSON.parse()メソッドの組み合わせにより、オブジェクトの深いコピーが作成されます。 JSON.stringify()オブジェクトを文字列に変換し、JSON.parse()文字列を新しいオブジェクトに解析します。ただし、この方法には、メソッドをコピーせず、DateRegExpMapSetなどの特別なJavaScriptオブジェクトには適していないため、いくつかの制限があります。

浅い複製の制限は何ですか?

浅いコピーは、ネストされたオブジェクトへの第1レベルの属性と参照のみを複製します。したがって、元のオブジェクトにネストされたオブジェクトが含まれている場合、それらのネストされたオブジェクトの変更は、元のオブジェクトとコピーされたオブジェクトに影響します。これにより、コードの予期しない結果とエラーが発生する可能性があります。

Object.assign()メソッドは浅いコピーでどのように機能しますか?

Object.assign()メソッドは、ターゲットオブジェクトに1つ以上のソースオブジェクトのすべての列挙可能なプロパティの値をコピーするために使用されます。ターゲットオブジェクトを返します。ただし、浅いコピーを実行します。つまり、最初のレベルのプロパティとネストされたオブジェクトへの参照のみをコピーすることを意味します。

JavaScriptでオブジェクトを深くコピーする最良の方法は何ですか?

JavaScriptでオブジェクトを深くコピーする最良の方法は、コードの特定の要件に依存します。オブジェクトにメソッドまたは特別なJavaScriptオブジェクトが含まれていない場合は、JSON.stringify()JSON.parse()メソッドの組み合わせを使用できます。より複雑なオブジェクトの場合、深いクローン機能を提供するLodashのようなライブラリを使用することをお勧めします。

ディープコピーに拡張オペレーターを使用できますか?

いいえ、JavaScriptの拡張演算子は浅いコピーのみを実行します。最初のレベルの属性とネストされたオブジェクトへの参照をコピーします。深い複製を実行するには、別の方法またはライブラリを使用する必要があります。

深い複製のパフォーマンスへの影響は何ですか?

深い複製は、特に大きなオブジェクトの場合、浅い複製よりも多くのリソースを消費する場合があります。これは、ディープコピーがすべてのネストされたオブジェクトに新しいインスタンスを作成し、より多くのメモリと処理能力を引き出すことができるためです。

深い複製で円形の参照を扱う方法は?

JSON.stringify()JSON.parse()などのディープコピーメソッドは、円形の参照を処理せず、エラーをスローします。オブジェクトのプロパティがオブジェクト自体を参照すると、円形の参照が発生します。円形の参照を処理するには、Lodashなどのそれをサポートするライブラリを使用する必要があります。

なぜ浅いコピーとディープコピーの違いを気にする必要があるのですか?

JavaScriptのデータを管理するには、浅い複製と深い複製の違いを理解することが重要です。オブジェクトが相互にどのように相互作用するかに影響します。注意しないと、浅いコピーは、ネストされたオブジェクトの変更が元のオブジェクトとコピーされたオブジェクトに影響するため、予期しない結果とエラーにつながる可能性があります。一方、ディープコピーは、コピーオブジェクトが元のオブジェクトから完全に独立していることを保証します。

以上がJavaScriptの浅いコピーとディープコピーの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。