js中常见的几种深拷贝方法

使用递归方式进行深拷贝

let deepClone = (initalObj) => {
    const obj = {};
    if(typeof initalObj !== 'object'){
      return initalObj
    }
    for (const key in initalObj) {
      if (typeof initalObj[key] === 'object') {
        //对数组特殊处理
        if (Array.isArray(initalObj[key])) {
          //用map方法返回新数组,将数组中的元素递归
          obj[key] = initalObj[key].map(item => this.deepClone(item))
        } else {
          //递归返回新的对象
          obj[key] = this.deepClone(initalObj[key]);
        }
      } else if (typeof initalObj[key] === 'function') {
        //返回新函数
        obj[key] = initalObj[key].bind(obj);
      } else {
        //基本类型直接返回
        obj[key] = initalObj[key];
      }
    }
    return obj;
  }

const obj = {
  a: 1,
  b: {},
  c: { d: {}, g: () => {} },
  e: () =>{},
  f: function () {}
}
const newObj = deepClone(obj);
newObj.a === obj.a  //true
newObj.b === obj.b  //false
newObj.c === obj .false  //false
newObj.c.d === obj.c.d  //false
newObj.c.g === obj.c.g  //false
newObj.e === obj.e  //false
newObj.f === obj.f  //false
  • 递归运行效率低,次数过多的话容易造成栈溢出。
  • 比较常用!兼容性好!

通过JSON序列化实现深拷贝

序列化后再反序列化。

 
function Clone(obj) {
    var Copyobj = JSON.stringify(obj),
      //json字符串转json对象
      objClone = JSON.parse(Copyobj);
    return objClone;
 }

注意,这种方法容易出很多问题,实际并不常用!

  • 如果obj里有RegExp、Error对象,则序列化的结果将只得到空对象

  • 如果obj里面有时间对象,则JSON.stringify后再JSON.parse的结果,时间将只是字符串的形式。而不是时间对象

  • 如果obj里有函数,undefined,则序列化的结果会把函数或 undefined丢失

  • 如果obj里有NaN、Infinity和-Infinity,则序列化的结果会变成null

  • 无法处理function,无法处理循环引用对象

lodash函数库实现深拷贝

var abj={
  a:1,
  b:2
}
var copyobj = lodash.cloneDeep(abj)

这个没啥好说的,就是调用库函数罢了,原理和第一个一样。

使用jq(extend)方法实现深拷贝

var obj= {
  a:10,
  b:function (){
    console.log(this.a)
  }
};
var newObj = $.extend(true,{},obj);

这个也没啥好说的,就是调用库函数…啊这

其他补充

slice()和concat()

使用slice、concat方法并不是真正的深拷贝!

它们只会复制第一层,而到了第二层及其之后,只会复制引用地址了!

使用方法如下:

  • 对于数组类型,可以使用slice(start, end)方法,返回一个新的数组。var arr1 = arr.slice(0);
  • 数组类型还可以使用concat()方法,var arr1 = arr.concat();

object.assign()

var obj1 = { a: 0 , b: { c: 0}};
var obj2 = Object.assign({}, obj1);

当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝

如果是有多层嵌套呢?

 var obj1 = {
    a: 1,
    b: 2,
    c: ['a','b','c']
}
var obj2 = Object.assign({}, obj1);
obj2.c[1] = 5;
console.log(obj1.c); // ["a", 5, "c"]
console.log(obj2.c); // ["a", 5, "c"]

可以看到对于一层对象来说是没有任何问题的,但是如果对象的属性对应的是其它的引用类型的话,还是只拷贝了引用,修改的话还是会有问题。

所以可知,对象中有对象的时候,此方法在二级属性以后就是浅拷贝。

总结

从原理上来说,只有以下两种方法是无论有多少层嵌套都能实现真正的深拷贝。

  • 自定义递归方法
  • json序列化

但是json序列化容易出bug,所以实际编写工具函数时,都会用第一种方法。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在编程,对象和数组的拷贝涉及到数据结构的副本创建,确保新创建的对象与原对象独立,即使原对象发生改变也不会影响副本。这里有几种常见拷贝方式: 1. **浅拷贝(Shallow Copy)**: 对于简单类型(如基本数据类型)或值类型,拷贝的是它们的值。对于复杂类型如数组或对象,浅拷贝实际上是创建了一个引用,两个变量指向的是同一个内存地址。这意味着对其一个的修改会影响到另一个。 2. **拷贝(Deep Copy)**: - **复制数组**:对于数组,可以逐个元素地进行拷贝,创建一个新的数组并填充每个元素的拷贝。例如,在JavaScript可以使用`JSON.parse(JSON.stringify(array))`来实现。 - **复制对象**: a. 使用构造函数:创建新对象,然后递归遍历原对象,为每个属性创建新的值,而不是引用。例如在JavaScript,`function deepCopy(obj) { return new obj.constructor(obj); }`。 b. 使用`Object.assign()`和扩展运算符...:结合使用,创建一个新的对象,并将所有属性从源对象复制过来,但不会创建循环引用。但是这种方法不适用于原型链的对象。 c. 库方法:有些编程语言有现成的库函数或模块可以直接完成拷贝操作,比如Python的`copy.deepcopy()`。 3. **度克隆(Deep Cloning)**: 术语"度克隆"通常用于描述度复制的过程,特别是在讨论复杂的数据结构,如树、图或对象树时。 **相关问题**: 1. 浅拷贝拷贝的主要区别是什么? 2. 如何在JavaScript避免对象属性的引用冲突进行拷贝? 3. 如果数组的元素是对象,应该如何正确地进行拷贝

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值