javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > JavaScript深拷贝实现

JavaScript实现深拷贝的不同方法汇总

作者:人才程序员

在JavaScript中,我们经常需要将一个对象的所有数据复制到另一个对象中,这种操作可以分为 浅拷贝 和 深拷贝,而深拷贝则是指完全复制一个对象及其所有嵌套的对象,而不仅仅是对象的引用,本文,我们将深入探讨深拷贝的概念,以及如何使用不同的方法实现深拷贝

1. 什么是深拷贝?

深拷贝(Deep Copy)是指创建一个新的对象,并且递归地复制原对象及其所有嵌套的子对象。这样,原对象和新对象之间就没有任何共享的引用,即修改新对象的属性不会影响原对象。

相对而言,浅拷贝(Shallow Copy)只是创建一个新对象,但只复制对象的第一层属性。如果原对象中某些属性是引用类型(例如数组或对象),那么拷贝的新对象和原对象中的这些属性仍然指向相同的内存地址(即引用相同的对象)。

深拷贝 vs 浅拷贝

特性浅拷贝深拷贝
复制层级仅复制第一层属性递归复制所有层级的属性
引用类型属性引用类型属性复制的是地址,即共享同一内存区域引用类型属性被完全复制,不再共享内存区域
修改后效果修改浅拷贝对象中的引用类型属性会影响原对象修改深拷贝对象中的引用类型属性不会影响原对象

2. 为什么要使用深拷贝?

我们使用深拷贝通常是为了确保复制的对象是完全独立的,即不受原对象的影响。常见的使用场景包括:

3. 深拷贝的实现方法

3.1 使用 JSON.parse() 和 JSON.stringify()

JSON.parse() 和 JSON.stringify() 是一种常见的深拷贝方法。它们通过将对象转换为字符串,然后再将字符串转换回对象的方式实现拷贝。

示例:使用 JSON.parse() 和 JSON.stringify()

const original = {
  name: "Alice",
  age: 30,
  address: {
    city: "New York",
    zip: "10001"
  }
};

const deepCopy = JSON.parse(JSON.stringify(original));

// 修改深拷贝对象
deepCopy.address.city = "Los Angeles";

console.log(original.address.city); // 输出:New York
console.log(deepCopy.address.city); // 输出:Los Angeles

这种方法非常简单,能够有效地复制大部分对象,但有一些限制:

3.2 使用递归实现深拷贝

我们可以手动实现一个深拷贝函数,通过递归的方式遍历对象的每一层,复制每一层的属性。这个方法比较灵活,能处理大多数场景。

示例:递归实现深拷贝

function deepClone(obj) {
  if (obj === null || typeof obj !== 'object') {
    return obj; // 如果是基本类型,直接返回
  }

  let copy;
  if (Array.isArray(obj)) {
    copy = [];
    for (let i = 0; i < obj.length; i++) {
      copy[i] = deepClone(obj[i]); // 递归复制数组元素
    }
  } else {
    copy = {};
    for (let key in obj) {
      if (obj.hasOwnProperty(key)) {
        copy[key] = deepClone(obj[key]); // 递归复制对象属性
      }
    }
  }

  return copy;
}

const original = {
  name: "Alice",
  age: 30,
  address: {
    city: "New York",
    zip: "10001"
  },
  hobbies: ["Reading", "Traveling"]
};

const deepCopy = deepClone(original);

// 修改深拷贝对象
deepCopy.address.city = "Los Angeles";
deepCopy.hobbies[0] = "Writing";

console.log(original.address.city); // 输出:New York
console.log(original.hobbies[0]);  // 输出:Reading
console.log(deepCopy.address.city); // 输出:Los Angeles
console.log(deepCopy.hobbies[0]);  // 输出:Writing

这个实现能够递归地处理对象和数组,也能处理嵌套的对象和数组。每个属性都会被复制,并且没有共享引用。

3.3 使用 structuredClone() (现代浏览器)

在现代 JavaScript 环境中,structuredClone() 方法是一个非常方便的深拷贝工具。它是浏览器提供的原生方法,可以克隆对象并保留原对象中的循环引用、DateMapSet 等特殊对象。

示例:使用 structuredClone()

const original = {
  name: "Alice",
  age: 30,
  address: {
    city: "New York",
    zip: "10001"
  },
  hobbies: ["Reading", "Traveling"]
};

const deepCopy = structuredClone(original);

// 修改深拷贝对象
deepCopy.address.city = "Los Angeles";
deepCopy.hobbies[0] = "Writing";

console.log(original.address.city); // 输出:New York
console.log(original.hobbies[0]);  // 输出:Reading
console.log(deepCopy.address.city); // 输出:Los Angeles
console.log(deepCopy.hobbies[0]);  // 输出:Writing

structuredClone() 不仅可以处理对象、数组,还能处理更多类型的对象,如 Map、Set 和 ArrayBuffer,并且支持循环引用。

3.4 使用第三方库(如 Lodash)

Lodash 提供了一个功能强大的深拷贝方法 _.cloneDeep(),它能够处理更多类型的对象,并且是一个非常稳定的实现。对于复杂应用,使用 Lodash 会更加简便和高效。

示例:使用 Lodash 的 _.cloneDeep()

// 需要引入 Lodash 库
const _ = require('lodash');

const original = {
  name: "Alice",
  age: 30,
  address: {
    city: "New York",
    zip: "10001"
  },
  hobbies: ["Reading", "Traveling"]
};

const deepCopy = _.cloneDeep(original);

// 修改深拷贝对象
deepCopy.address.city = "Los Angeles";
deepCopy.hobbies[0] = "Writing";

console.log(original.address.city); // 输出:New York
console.log(original.hobbies[0]);  // 输出:Reading
console.log(deepCopy.address.city); // 输出:Los Angeles
console.log(deepCopy.hobbies[0]);  // 输出:Writing

Lodash 的 cloneDeep() 函数可以处理复杂的对象,包括嵌套的对象、数组、MapSet 等,且避免了我们手动实现深拷贝时可能遇到的坑。

4. 深拷贝的限制

虽然深拷贝非常有用,但它也有一些限制和性能问题:

5. 总结

深拷贝是克隆 JavaScript 对象时的一个重要技术,它能够确保新对象与原对象完全独立。在实现深拷贝时,我们可以选择使用简单的 JSON 方法、递归方法、现代 API structuredClone(),或者使用强大的第三方库(如 Lodash)。

深拷贝的核心思想是递归地复制对象的每一层,并确保没有共享引用。掌握深拷贝的实现可以帮助你更好地管理复杂的数据结构,避免不必要的副作用。

以上就是JavaScript实现深拷贝的不同方法汇总的详细内容,更多关于JavaScript深拷贝实现的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文