【インタビュー質問】JavaScriptのディープコピーとシャローコピー:原理と実装

大昌面接の質問は面接の質問バンクを共有します

フロントエンドとバックエンドのインタビューの質問バンク (インタビューに必要) 推奨: ★★★★★

住所:フロントエンド面接問題バンク  Web フロントエンド面接問題バンク VS Java バックエンド面接問題バンク Daquan

序文

  在开发过程中,我们经常会遇到需要复制一个对象或数组的情况。在 JavaScript 中,我们可以使用浅拷贝或深拷贝来实现复制功能。浅拷贝只会复制对象或数组的第一层属性,如果属性的值还是对象或数组,那么它们之间的引用关系并不会改变。相反,深拷贝会完全复制对象或数组的所有属性,并创建新的引用关系。

  在什么情况下需要使用深拷贝呢?通常来说,当我们希望对象或数组的改变不影响原对象或数组时,就需要使用深拷贝。例如,我们可能希望在处理数据的过程中保留原始数据的副本,或者在修改一个对象的属性时不影响原对象。在本文中,我们将介绍 JavaScript 中的深拷贝方法,并给出使用深拷贝的示例代码。

复制代码

1. ディープコピーとシャローコピーとは?

  在 JavaScript 中,对象和数组都是引用类型,它们的值是存储在内存中的地址,而不是实际的值。当我们复制一个对象或数组时,如果我们只是复制它们的地址,那么原来的对象或数组和新的对象或数组都指向同一个地址,对其中一个对象或数组的修改会影响另一个对象或数组。这种复制方式称为浅拷贝。为了避免这种情况,我们需要进行深拷贝,即复制对象或数组的值,而不是复制地址。
复制代码

2.ディープコピーの実現

 深拷贝的方法有很多种,常见的方法包括使用 `JSON.parse` 和 `JSON.stringify`、使用递归算法、使用 lodash 等。
复制代码

2.1 ディープコピーの使用JSON.parse と 作成JSON.stringify

ディープ コピーを使用して JSON.parse 実行 する方法は非常に簡単です。コピーするオブジェクトまたは配列を 文字列に変換し、それを使用して  文字列を元のオブジェクトまたは配列に変換するJSON.stringify だけです 。JSON.stringifyJSON.parse

 ディープ コピーの使用方法 JSON.parse と 作成方法を示す簡単な例を次に示します。JSON.stringify

const original = { a: 1, b: { c: 2 } };

// 使用 JSON.stringify 将对象转化为字符串,再使用 JSON.parse 将字符串转回对象
const copy = JSON.parse(JSON.stringify(original));

console.log(original === copy); // false
console.log(original.b === copy.b); // false
复制代码

この例では、最初にネストされたオブジェクトを含むオブジェクトを定義し original、次にディープ コピーを使用して JSON.parse 新しい JSON.stringify オブジェクトを取得します copy最後に、演算子を使用して === 、2 つのオブジェクトが等しいかどうか、および 2 つのオブジェクトのネストされたオブジェクトが等しいかどうかを比較し、2 つのオブジェクトと 2 つのネストされたオブジェクトが等しくないことを確認します。これは、ディープ コピーが作成されたことを示します。

2.2 再帰アルゴリズムによるディープコピーの実現

  使用 `JSON.parse` 和 `JSON.stringify` 进行深拷贝也有一些限制,比如不能复制函数、Symbol 等类型的值,也不能正确地复制循环引用的对象。

  因此,在实际应用中,我们还需要考虑使用其他的深拷贝方法来解决这些限制,例如递归算法实现深拷贝,它可以递归地复制对象或数组的值,并判断是否为基本类型(如数字、字符串、布尔值等),如果是基本类型就直接返回,否则就继续递归复制。
复制代码

以下は、再帰アルゴリズムを使用してディープ コピーを実装する例です。

function deepCopy(obj) {
  if (typeof obj !== 'object' || obj === null) {
    return obj;
  }

  // 判断是数组还是对象
  const isArray = Array.isArray(obj);
  const copy = isArray ? [] : {};

  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      copy[key] = deepCopy(obj[key]);
    }
  }

  return copy;
}

const original = { a: 1, b: { c: 2 } };
const copy = deepCopy(original);

console.log(original === copy); // false
console.log(original.b === copy.b); // false
复制代码

この例では、 deepCopy オブジェクトまたは配列を引数として取り、ディープ コピーを作成する という名前の関数を定義します。まず、 typeof 演算子を使用して、入力パラメーターがオブジェクトか配列かを判断し、そうでない場合は直接返します。次に、 Array.isArray 関数を使用して、入力パラメーターが配列かオブジェクトかを判断し、新しい配列またはオブジェクトを作成します。最後に、ループを使用してオブジェクトまたは配列のプロパティを反復処理し、再帰を使用して deepCopy 関数を呼び出してプロパティの値をコピーします。

再帰アルゴリズムを使用してディープ コピーを実装する方法は比較的複雑ですが、関数、シンボル、循環参照オブジェクトなどの型の値を正しくコピーできるという明らかな利点があります。

2.2 ディープコピーを利用する際の注意点は?

  1. 生データの種類に関する問題

ディープコピーを使用する場合、一部のタイプのデータはディープコピー後に変更される可能性があることに注意する必要があります。たとえば、  JSON.parse() and JSON.stringify() 関数を使用すると関数が文字列に変換され、再帰関数を使用すると正規表現が空のオブジェクトに変換されます。

  1. 浅いコピーに関する問題

場合によっては、オブジェクトまたは配列の一部のプロパティをディープ コピーするのではなく、シャロー コピーを使用する必要があります。これは、カスタム再帰関数で実現できます。たとえば、ディープ コピーを必要としない属性を示すブラックリストを設定できます。

3. シャローコピーの実装

浅いコピーとは、オブジェクトまたは配列をコピーするときに、その第 1 レベルの属性のみがコピーされ、その属性の値はコピーされないことを意味します (属性の値がまだオブジェクトまたは配列である場合)。したがって、シャロー コピーによって取得された新しいオブジェクトまたは配列と、元のオブジェクトまたは配列の間には参照関係が引き続き存在します

JavaScript では、次のメソッドを使用して浅いコピーを実現できます。

  • 拡散演算子 ( ...) を使用: let newArray = [...oldArray],let newObject = {...oldObject}
  • 使用 Object.assign() 機能:let newObject = Object.assign({}, oldObject)
  • 配列を操作する 関数slice() またはオブジェクトを 操作する関数Object.keys() : let newArray = oldArray.slice(),let newObject = Object.keys(oldObject).reduce((acc, key) => ({...acc, [key]: oldObject[key]}), {})

3.1 シャローコピーの適用シナリオ

  与深拷贝相比,浅拷贝的实现方法要简单得多,但是它的功能也相对较弱。如果我们希望复制对象或数组的所有属性,并创建新的引用关系,还是需要使用深拷贝,但是在某些情况下,我们可能希望使用浅拷贝。
复制代码
  • 新しいオブジェクトまたは配列を構築する必要がある場合、浅いコピーを使用したい場合があります。浅いコピーは第 1 レベルの属性のみをコピーするため、コピーの時間とスペースを節約できます。たとえば、浅いコピーを使用して、元の配列のすべての要素を含む新しい配列を作成できますが、元の配列のプロパティは含まれません。

  • 浅いコピーは、オブジェクトまたは配列の一部のプロパティをコピーする場合にも使用できます。たとえば、スプレッド演算子または Object.assign() 関数を使用して、オブジェクトの一部のプロパティをコピーできます。これにより、必要なプロパティのみをコピーするため、コピーの時間とスペースを節約できます。

つまり、浅いコピーは特定のシナリオで非常に役立ちますが、その機能は比較的弱いものです。実際の状況に応じて、浅いコピーを使用することを選択する必要があります

3.2 シャローコピーの実装方法

いくつかの一般的な方法を次に示します。

  1. スプレッド演算子 (...) を使用します。
function shallowClone(obj) {
  return {...obj};
}
复制代码
  1. 使用 Object.assign() 機能:
function shallowClone(obj) {
  return Object.assign({}, obj);
}
复制代码
  1. 組み込みのコンストラクターを使用します。
function shallowClone(obj) {
  if (obj === null || typeof obj !== 'object') {
    return obj;
  }
  let clone = new obj.constructor();
  for (let key in obj) {
    clone[key] = obj[key];
  }
  return clone;
}

let obj = {a: 1, b: 2, c: [3, 4, 5]};
let shallow = shallowClone(obj);
console.log(shallow); // {a: 1, b: 2, c: [3, 4, 5]}
复制代码

4. まとめ

最后,在使用深浅拷贝时,我们要根据实际的需求来决定使用哪种方法,并确保复制的对象或数组能够满足我们的需求。
复制代码

参考になればいいね、間違いがあればご指摘ください あなたと同じように風を追う青年CoderBugです!

大昌面接の質問は面接の質問バンクを共有します

フロントエンドとバックエンドのインタビューの質問バンク (インタビューに必要) 推奨: ★★★★★

住所:フロントエンド面接問題バンク  Web フロントエンド面接問題バンク VS Java バックエンド面接問題バンク Daquan

 

おすすめ

転載: blog.csdn.net/weixin_42981560/article/details/130136418