带你搞懂js的深拷贝

带你搞懂js的深拷贝

在JavaScript中,拷贝是一项非常重要的任务,因为在JavaScript中,赋值操作并不是简单的复制一个变量的值到另一个变量,而是复制该变量所持有的引用地址,这意味着如果你直接将一个变量赋值给另一个变量,那么两者将共享同一份数据,即数据的修改将会同步。因此,当你需要对数据进行操作和修改时,深拷贝是至关重要的。

深拷贝的实现

实现一个深拷贝的算法可以分为两个步骤:

  1. 将对象进行递归拷贝或者循环拷贝
  2. 将拷贝后的对象返回

递归拷贝

某些情况下,递归拷贝可以比循环拷贝更简单和可读性更好。一个基本的递归拷贝的实现如下:

function deepClone(obj) {
  if (obj === null) return null; // 判断null

  if (typeof obj !== 'object') return obj; // 判断基本类型,直接返回

  if (obj.constructor === Date) return new Date(obj); // 判断Date类型
  if (obj.constructor === RegExp) return new RegExp(obj); // 判断RegExp类型

  const newObj = new obj.constructor(); // 通过构造函数创建对象

  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      newObj[key] = deepClone(obj[key]); //递归拷贝
    }
  }

  return newObj; // 返回新对象
}

循环拷贝

循环拷贝是另一种实现深拷贝的方式,使用循环拷贝的好处是可以避免递归深度过深导致的栈溢出问题。一个基本的循环拷贝的实现如下:

function deepClone(obj) {
  const stack = [];
  const newObj = new obj.constructor();

  stack.push({
    parent: newObj,
    key: undefined,
    data: obj
  });

  while (stack.length !== 0) {
    const node = stack.pop();
    const { parent, key, data } = node;

    if (typeof data === 'object') {
      const clone = new data.constructor();
      Object.defineProperty(parent, key, {
        value: clone,
        writable: true,
        enumerable: false,
        configurable: true
      });
      for (let i in data) {
        stack.push({
          parent: clone,
          key: i,
          data: data[i]
        });
      }
    } else {
      Object.defineProperty(parent, key, {
        value: data,
        writable: true,
        enumerable: false,
        configurable: true
      });
    }
  }

  return newObj;
}

在这个实现中,我们使用了一个栈(stack)来模拟递归过程。栈中每个元素代表了原始对象的一个属性,并且保存了当前拷贝对象上一级的父级、当前属性的键以及该属性所指向的原始对象。

示例说明

下面给短示两个简单的例子,帮助理解深拷贝过程。

示例 1:

const a = { name: 'Tom', birthday: new Date() };
const b = deepClone(a);
console.log(b); // { name: 'Tom', birthday: Date }

a.birthday.setFullYear(2000);
console.log(a.birthday); // 2000-xx-xx
console.log(b.birthday); // 当前日期

在这个例子中,我们定义了一个含有Date类型属性的对象,在将该对象深拷贝后,修改原始数据的Date类型属性,不会影响拷贝后的数据。

示例 2:

const a = { name: 'Tom', friends: ['Jerry', 'Bob'] };
const b = deepClone(a);
console.log(b); // { name: 'Tom', friends: ['Jerry', 'Bob'] }

a.friends.push('Kate');
console.log(a.friend); // ['Jerry', 'Bob', 'Kate']
console.log(b.friend); // ['Jerry', 'Bob']

在这个例子中,我们定义了一个含有数组属性的对象,在将该对象深拷贝后,修改原始数据的数组属性,不会影响拷贝后的数据。这是因为深拷贝过程中,数组被拷贝为一个新的数组,拥有自己的内存空间,不会受到原始数据的影响。

结语

关于JavaScript的深拷贝还有很多细节和实现方式,这里只提供了一个基本的模板和两个简单的示例。希望可以帮助你更好地理解深拷贝的概念和实现。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:带你搞懂js的深拷贝 - Python技术站

(0)
上一篇 2023年5月27日
下一篇 2023年5月27日

相关文章

  • javascript实现将文件保存到本地方法汇总

    当用户需要在浏览器中将文件保存到本地时,可以使用JavaScript实现该功能,以下是实现该功能的一些方法。 方法一:使用HTML5的download属性 可以使用HTML5的下载属性(download attribute)来实现将文件保存到本地。将download属性添加到<a>标签或<button>标签中,并将href属性设置为文…

    JavaScript 2023年5月27日
    00
  • 在vs2010中调试javascript代码方法

    在VS2010中调试JavaScript代码,需要注意以下几个步骤: 1. 确认浏览器设置 在VS2010中调试JavaScript代码,需要使用Internet Explorer浏览器。因此,需要先确认IE浏览器的设置是否正确。 打开IE浏览器,选择菜单栏-工具-Internet选项。 在Internet选项窗口中,点击“高级”选项卡。 确认“禁用脚本调试…

    JavaScript 2023年6月11日
    00
  • javascript 用函数实现继承详解

    下面是“javascript 用函数实现继承详解”的完整攻略,内容包括以下几部分: 什么是继承? 原型链继承 借用构造函数实现继承 组合继承 原型式继承 寄生式继承 寄生组合式继承 什么是继承? 继承是 JavaScript 中的一个重要概念,它允许我们可以在已有对象的基础上创建新的对象,并继承已有对象的属性和方法。通过继承,我们可以大大提高代码重用的效率,…

    JavaScript 2023年5月27日
    00
  • js实现分割上传大文件

    实现分割上传大文件有几种不同的方法,其中一种比较流行的方式是将文件拆分成多个分片,然后分别上传,最后合并成完整的文件。以下是实现该方法的完整攻略。 1. 拆分文件 首先,我们需要将要上传的大文件拆分成若干个分片。拆分文件的大小可以定为50MB-100MB左右,但具体大小根据需要和实际情况而定。以下示例代码使用FileReader来读取文件数据并拆分文件。 c…

    JavaScript 2023年5月27日
    00
  • 比较JavaScript对象的四种方式

    当我们需要比较两个 JavaScript 对象时,有四种方法可供选择。 1. 使用 JSON.stringify() 将对象转换为字符串比较 我们可以使用 JSON.stringify() 方法将对象转换为字符串,然后进行比较。这种方法的优点是简单易懂,适用于大多数情况。但是,它无法比较对象内部的属性顺序。 下面是使用 JSON.stringify() 方法…

    JavaScript 2023年5月27日
    00
  • 9个让JavaScript调试更简单的Console命令

    9个让JavaScript调试更简单的Console命令 在日常的JavaScript开发过程中,我们经常需要进行调试。而控制台(Console)是我们不可或缺的调试工具之一。在Chrome浏览器中,Console提供了许多有用的命令,下面将介绍9个让JavaScript调试更简单的Console命令。 log() 用来在控制台输出信息,是开发中最常用的调试…

    JavaScript 2023年5月28日
    00
  • assert()函数用法总结(推荐)

    当我们编写程序时,为了保证程序的正常运行,需要对程序中的各个部分进行测试和验证。而assert()函数就是一个非常常用的测试和验证工具。 assert()函数介绍 assert()函数是C语言头文件中的一种调试工具,包含于库中。其作用是,如果传入的参数为0(即假),则表达式为false,会触发assert()函数,程序将会停止运行。assert()函数用于检…

    JavaScript 2023年6月10日
    00
  • 简易版本JSON.stringify的实现及其六大特性详解

    下面我来讲解“简易版本JSON.stringify的实现及其六大特性详解”的攻略。 前言 在日常的开发中,我们经常会用到JSON.stringify方法来将Javascript对象转换成JSON格式的字符串,可以方便地实现客户端和服务器端之间的数据交互。但是,我们并不总是清楚其内部是如何工作的。在本攻略中,我将给大家介绍如何用简易版本实现JSON.strin…

    JavaScript 2023年5月27日
    00
合作推广
合作推广
分享本页
返回顶部