Skip to content

关于深拷贝

在做项目时遇到了表单填写后,不点击提交或确定,其数据也发生了变化

这时候,我们需要使用到深拷贝去解决这个问题:

深拷贝:创建一个新的对象和数组,将原对象的各项属性的"值"(数组的所有元素)拷贝过来,是"值"而不是"引用",新对象跟原对象不共享内存,修改新对象不会影响到原对象。

浅拷贝(Shallow Copy):将原对象的引用复制给新对象,新对象与原对象共享同一个内存地址,修改新对象会影响原对象,反之亦然。浅拷贝只复制了对象的引用,而没有复制对象本身。

解决方法一

将数据库获取数据赋值到一个tempIndex中(非表单中的数据),当点击按钮修改非表单数据时深拷贝tempIndex,赋值到index,在表单中对index做修改,点击确定或提交,把数据发送至后端,这样在没有点击确定或提交时原数据才不会跟着改变。

缺点

仅能用于防止意外修改,未实现深拷贝

解决方法二

javascript
function cloneJSON(source) {
    return JSON.parse(JSON.stringify(source));
}

通过将对象转换为 JSON 字符串,然后再将 JSON 字符串解析为新对象的方式实现深拷贝,适用于大多数简单的对象和数组

  1. 使用 JSON.stringify(source) 将源对象(source)序列化为 JSON 字符串。这个过程会将对象的所有属性和值转换为字符串表示。

  2. 使用 JSON.parse() 将 JSON 字符串解析为新的对象。这个过程会创建一个新的对象,其中包含源对象的所有属性和值的拷贝。

缺点

  • 无法处理循环引用的对象。如果对象中存在循环引用,JSON.stringify() 会抛出错误。
  • 无法拷贝函数、正则表达式、Symbol 类型等特殊对象。这些对象在序列化和解析过程中会丢失。
  • 无法保留对象的原型链。新对象的原型链会被重置为 Object.prototype

解决方法三:递归实现

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

  let clone = Array.isArray(obj) ? [] : {};

  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      clone[key] = deepClone(obj[key]);
    }
  }

  return clone;
}
  1. 在循环中,函数使用 hasOwnProperty() 方法来检查属性是否为 obj 自身的属性,以避免拷贝原型链上的属性。

  2. 对于每个属性,函数递归调用 deepClone() 函数来拷贝属性的值,并将拷贝后的值赋给 clone 对应的属性。

能够处理复杂的对象结构,包括嵌套的对象和数组。它会递归地遍历对象的所有属性,并对每个属性进行深拷贝。这样可以确保拷贝后的对象与原始对象完全独立,互不影响。

缺点

  • 仍然无法处理循环引用的对象,因为递归调用会导致无限循环。

  • 无法拷贝函数、正则表达式、Symbol 类型等特殊对象。

解决方法四:使用第三方库

lodash 是一个流行的 JavaScript 工具库,提供了许多实用的功能,包括深拷贝。您可以使用 lodash 的 cloneDeep 函数实现深拷贝:

javascript
const _ = require('lodash');

const newObj = _.cloneDeep(oldObj);

Released under the MIT License.