JS实现数组深拷贝的方法分析

yizhihongxing

下面是一份详细的“JS实现数组深拷贝的方法分析”的攻略:

背景

在使用 JavaScript 中的数组时, 如果我们要将一个数组赋值给另一个变量, 只是简单地将数组变量赋给另一个变量,这样会导致两个变量指向同一个数组引用,即两个数组变量会指向同一个数组对象,如果只是数组的一些简单操作,这不会产生什么问题, 但如果涉及到多次修改某个数组,这时不停地修改一个数组会引用到其他变量之前时的状态,这样会影响程序运行结果。这时候,就需要对数组进行深拷贝。

方法

数组深拷贝有很多方法,比如使用 JSON 库深度复制、使用递归实现深度克隆、使用 ES6 的扩展符等等。下面将介绍其中两个方法:

方法一:JSON 库转换

const arr1 = [1, 2, { a: 3 }];
const arr2 = JSON.parse(JSON.stringify(arr1));

JSON 库中有两个方法:JSON.stringify()JSON.parse(),可以将任意复杂的东西转换成 JSON 字符串,再将这个 JSON 字符串解析成对象。在深拷贝数组中,我们可以利用 JSON 库的这两个方法:先把数组变成 JSON 字符串,再通过解析 JSON 字符串变成对象,从而达到深拷贝的目的。

但是,这种方法的缺陷是:它不能拷贝函数、正则、Date 等引用类型的值。

方法二:递归实现深度克隆

递归地从最简单的数据类型开始,每次返回时都进行一次克隆。遇到对象时,继续进行递归。

function deepClone(obj) {
  if (obj === null) {
    return null;
  }
  if (typeof obj !== "object") {
    return obj;
  }
  if (obj instanceof Date) {
    return new Date(obj.getTime());
  }
  if (obj instanceof RegExp) {
    return new RegExp(obj);
  }
  const newObj = new obj.constructor();
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      newObj[key] = deepClone(obj[key]);
    }
  }
  return newObj;
}

const arr1 = [1, 2, { a: 3 }];
const arr2 = deepClone(arr1);

这种方法是通过递归实现深拷贝的。当拷贝的是基本类型时,直接返回该值,当是引用类型的时候,递归地拷贝该引用类型的值,并返回相应的克隆对象。这种方法比较完美地解决了 JSON 库方法的缺陷。

示例

下面两个示例将说明这两种方法分别是如何实现数组深拷贝的:

示例一:JSON 库转换

const arr1 = [1, 2, { a: 3 }, function () { console.log('hello') }];
const arr2 = JSON.parse(JSON.stringify(arr1));
arr2[2].a = 100;
console.log(arr1, arr2); // [1, 2, { a: 3 }, [Function]] [1, 2, { a: 100 }, null]

在这个示例中,我们把数组 arr1 赋值给 arr2 并使用 JSON 序列化和反序列化来完成深度复制。然后我们修改 arr2 的第三个元素,并输出 arr1 和 arr2。可以看到,虽然我们仅仅是修改了 arr2 的第三个元素,但 arr1 也跟着变了,即两个数组的第三个元素是不同的。

示例二:递归实现深度克隆

function deepClone(obj) {
  if (obj === null) {
    return null;
  }
  if (typeof obj !== "object") {
    return obj;
  }
  if (obj instanceof Date) {
    return new Date(obj.getTime());
  }
  if (obj instanceof RegExp) {
    return new RegExp(obj);
  }
  const newObj = new obj.constructor();
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      newObj[key] = deepClone(obj[key]);
    }
  }
  return newObj;
}

const arr1 = [1, 2, { a: 3 }, function () { console.log('hello') }];
const arr2 = deepClone(arr1);
arr2[2].a = 100;
console.log(arr1, arr2); // [1, 2, { a: 3 }, [Function]] [1, 2, { a: 100 }, [Function]]

在这个示例中,我们使用递归方式来实现数组的深拷贝,同时也打印出 arr1 和 arr2 以验证两个数组对象的不同。由于我们使用了递归方式实现深拷贝,因此即使修改了 arr2 的第三个元素,arr1 也不会受到影响,两个数组对象是相互独立的。

结论

通过上面的两个示例,我们可以明确“JS实现数组深拷贝的方法分析”的攻略。

总的来说,利用 JSON 库的方法实现数组的深拷贝是最简单的方法,只需一些简单的代码即可。但是它有明显的缺陷,即无法深拷贝 Date、正则、函数等引用类型的值。

递归方式实现深拷贝是比较完美的解决方案,但需要考虑的细节会比较多,比如如何判断一个值是不是基本类型。如果拷贝的对象过于复杂,则递归方法的效率也比较低。

在实际应用中,需要根据具体的业务需求和性能要求选择不同的实现方法。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:JS实现数组深拷贝的方法分析 - Python技术站

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

相关文章

  • 用json方式实现在 js 中建立一个map

    在 Javascript 中建立一个 Map,在较早版本的 Javascript 中是无法直接实现的,但我们可以使用 JSON 格式实现一个类似 Map 的数据结构。 具体实现过程: 首先定义一个 JSON 对象来表示 Map,将每个键值对当作 JSON 对象的一个属性,键作为属性名,值作为属性值。例如,要建立一个键为 “key1″,值为 1 的 Map: …

    JavaScript 2023年5月27日
    00
  • js数组去重的11种方法

    下面是详细讲解“js数组去重的11种方法”的完整攻略。 引言 在JavaScript开发中,常常需要我们对数组进行去重的操作。由于JavaScript本身没有提供去重的方法,开发者需要结合一些技巧和方法来完成这个任务。本文将由浅入深介绍11种JavaScript数组去重的方法,希望对大家有所帮助。 方式一:使用Set类型 Set是一种新的ES6数据类型,它存…

    JavaScript 2023年5月27日
    00
  • js中Generator函数的深入讲解

    关于 “js 中 Generator 函数的深入讲解”,以下是完整攻略: 什么是 Generator 函数? 简单来说, Generator 函数是 ES6 新增的一种异步编程解决方案,它返回一个迭代器对象,可以使用 yield 关键字定义函数内部的状态。调用迭代器对象的 .next() 方法可以将函数暂停或继续执行,每次执行 .next() 方法的返回结果…

    JavaScript 2023年5月27日
    00
  • 微信小程序实现animation动画

    以下是“微信小程序实现animation动画”的完整攻略: 1. 先了解animation动画 在微信小程序中,我们可以使用wx.createAnimation()方法来创建一个动画对象。这个方法返回的是Animation对象,我们可以使用这个对象来定义一系列动画帧,最后开始执行这些帧达到动画效果。 2. 创建Animation对象 要创建Animation…

    JavaScript 2023年6月10日
    00
  • 详解webpack打包后如何调试的方法步骤

    当你使用webpack进行打包时,有时候会出现一些问题,此时你需要调试打包后的代码。下面是一些详细的步骤,可以帮助你进行webpack打包后的代码调试。 1. 启用source maps 开启source maps可以让你在浏览器console中看到打包前的代码,这将大大方便你对代码进行调试。 在webpack的配置文件中,可以使用devtool选项来启用s…

    JavaScript 2023年6月10日
    00
  • js跳转页面方法总结

    JS跳转页面方法总结 在Web开发中,JS跳转页面是非常常见的操作。下面我们来总结几种JS跳转页面的方法。 方法一:使用JavaScript中的location对象 可以通过JavaScript提供的location对象来实现跳转页面的功能。使用方法如下: // 跳转到指定URL location.href = "http://www.exampl…

    JavaScript 2023年6月11日
    00
  • JavaScript事件委托

    JavaScript 事件委托是一种常用的编程技巧,它可以避免为每个元素添加事件监听器。事件委托背后的思想是,将事件监听器添加到其父元素上,而不是为每个子元素添加监听器。当事件触发时,事件将从子元素冒泡到其父元素,由父元素的事件监听器处理。这种技巧可以减少代码量,提高性能。 以下是一个完整的 JavaScript 事件委托攻略: 1. 理解事件冒泡和捕获 事…

    Web开发基础 2023年3月30日
    00
  • JavaScript中eval和with语句如何影响作用域链的深度探索

    让我详细讲解一下“JavaScript中eval和with语句如何影响作用域链的深度探索”。 什么是作用域链 在深入探索eval和with语句影响作用域链之前,我们需要了解一下什么是作用域链。 作用域链是JavaScript中的一个重要概念,它是一种链式结构,用于描述变量和函数的可见性和访问性。当我们访问一个变量或函数时,JavaScript引擎首先在当前作…

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