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

 更新时间:2025年06月20日 10:10:24   作者:人才程序员  
在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

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

  • 不能拷贝函数、undefinedSymbolRegExp 等特殊对象。
  • 会丢失对象的 prototype
  • 不能处理循环引用的对象。

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. 深拷贝的限制

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

  • 性能开销:深拷贝需要递归遍历所有属性,尤其是在对象层级较深或者属性较多时,会导致性能下降。
  • 无法复制一些特殊对象:如 function、undefined、RegExp、Symbol 等,这些需要额外处理。
  • 循环引用:有些深拷贝方法(如 JSON.parse())无法处理循环引用,而需要通过特殊的技巧来避免死循环。

5. 总结

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

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

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

相关文章

  • 防止文件缓存的js代码

    防止文件缓存的js代码

    原理其实就是通过在固定地址后面,加上一个不同值的日期数值,以达到地址不重复的目的,让浏览器每次都实时加载,不从缓存中读取文件
    2013-01-01
  • 原生javascript+CSS实现轮播图效果

    原生javascript+CSS实现轮播图效果

    这篇文章主要为大家详细介绍了原生javascript+CSS实现轮播图效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • js实现iPhone界面风格的单选框和复选框按钮实例

    js实现iPhone界面风格的单选框和复选框按钮实例

    这篇文章主要介绍了js实现iPhone界面风格的单选框和复选框按钮,涉及javascript动态操作页面元素样式的相关技巧,非常美观大方,需要的朋友可以参考下
    2015-08-08
  • JavaScript中原型链存在的问题解析

    JavaScript中原型链存在的问题解析

    本文通过实例给大家介绍js原型链存在的问题解析,非常不错,具有参考借鉴价值,感兴趣的朋友一起看看吧
    2016-09-09
  • JavaScript打印iframe内容示例代码

    JavaScript打印iframe内容示例代码

    打印iframe内容的方法有很多,下面为大家简单介绍下使用JavaScript实现打印,有需求的朋友可以参考下
    2013-08-08
  • JavaScript删除对象的不必要的属性

    JavaScript删除对象的不必要的属性

    这篇文章主要给大家介绍了JavaScript删除对象的不必要的属性,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-10-10
  • javascript数组遍历for与for in区别详解

    javascript数组遍历for与for in区别详解

    这篇文章主要介绍了javascript数组遍历for与for in区别,是篇非常不错的文章,这里推荐给小伙伴们。
    2014-12-12
  • JS数组索引检测中的数据类型问题详解

    JS数组索引检测中的数据类型问题详解

    这篇文章主要给大家介绍了关于JS数组索引检测中的数据类型问题的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • JS 可选链的三种形势及好处详解

    JS 可选链的三种形势及好处详解

    这篇文章主要为大家介绍了JS 可选链的三种形势及好处详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-05-05
  • MSN消息提示类

    MSN消息提示类

    MSN消息提示类...
    2006-09-09

最新评论