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

news/2024/7/19 16:23:42 标签: js, javascript

文章目录

  • 使用递归方式进行深拷贝
  • 通过JSON序列化实现深拷贝
  • lodash函数库实现深拷贝
  • 使用jq(extend)方法实现深拷贝
  • 其他补充
    • slice()和concat()
    • object.assign()
  • 总结

使用递归方式进行深拷贝

javascript">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序列化实现深拷贝

序列化后再反序列化。

javascript"> 
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函数库实现深拷贝

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

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

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

javascript">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()

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

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

如果是有多层嵌套呢?

javascript"> 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,所以实际编写工具函数时,都会用第一种方法。


http://www.niftyadmin.cn/n/555306.html

相关文章

使用 SourceTree 遇到冲突的解决方法

首先,更新代码之前先 git stash ,然后 git pull ,再 git stash pop 这时候如果本地改的代码跟线上的冲突了,就报错了.那么就需要手动解决冲突。 打开存在冲突的文件&#xff0c;会看到如下标志&#xff1a; <<<<<<<标记冲突开始&#xff0c;后面跟的是当…

常用的选择器(1)

1.元素选择器 作用&#xff1a;通过元素选择器可以通过标签名选中页面中指定的所有元素 语法&#xff1a; 标签名{ } 例子&#xff1a; <style type"text/css"> p{color:red;font-size; } </style> <body> <p>这是p标签</p> <bod…

一文带你彻底搞懂js的Array.prototype.reduce()方法!

文章目录定义和用法语法示例1、求数组中所有元素的值的和2、求对象数组中指定属性值的和3、将二维数组中的每个子数组元素进行合并&#xff0c;即二维数组扁平化4、统计数组元素的频数5、分组6、结合"..."使用7、数组元素的去重8、遍历数组&#xff0c;同时对符合条件…

python 从0学起

一&#xff0c;安装python 二&#xff0c;hello&#xff0c;world&#xff01; print("你好&#xff0c;世界&#xff01;"); Python中默认的编码格式是 ASCII 格式&#xff0c;在没修改编码格式时无法正确打印汉字&#xff0c;所以在读取中文时会报错。 解决方法为…

移动端的三种适配

移动端的三种适配 适配的目的&#xff1a;实现等比效果&#xff01;&#xff08;如果屏幕宽度是320px&#xff0c;元素宽度是160px&#xff0c;想要在不同屏幕中都占据一半的大小&#xff0c;此时我们就需要适配&#xff09;。 默认情况下不等比&#xff1a;不加meta标签时是等…

自己动手实现一个Array.prototype.reduce?

文章目录定义和用法语法自己实现一个队列实现递归实现遍历数组实现参考资料定义和用法 reduce是数组内置的一个方法&#xff0c;原型链上位于Array.prototype.reduce() reduce() 方法接收一个函数作为累加器&#xff0c;数组中的每个值&#xff08;从左到右&#xff09;开始缩…

网页布局方式:浮动和定位

1.文档流 文档流时整个页面的最底层&#xff0c;在页面中创建元素时默认情况下都在文档流。 元素在文档流里面的特点&#xff1a; 块元素&#xff1a;1&#xff09;块元素在文档流里会独占一行&#xff0c;块元素会自上向下垂直排列&#xff1b;2&#xff09;块元素在文档流中…

029_mac下nginx管理

一、 brew info nginx #查看nginx信息 nginx: stable 1.13.12 (bottled), HEAD Docroot is: /usr/local/var/wwwThe default port has been set in /usr/local/etc/nginx/nginx.conf to 8080 so that nginx can run without sudo.nginx will load all files in /usr/local/…