彻底理解JavaScript中的深拷贝和浅拷贝(1)

本文介绍了JavaScript中数组(Array)和对象(Object)的浅拷贝与深拷贝的区别,重点展示了`slice()`、`concat`、`Array.from()`、`Object.assign()`、`JSON.parse(JSON.stringify())`和递归方法在深拷贝中的作用。同时提到了循环引用拷贝的问题和解决方案,以及第三方库如jQuery和lodash的深拷贝工具。
摘要由CSDN通过智能技术生成

Array

var arr1 = [1, 2], arr2 = arr1.slice();

console.log(arr1); //[1, 2]

console.log(arr2); //[1, 2]

arr2[0] = 3; //修改arr2

console.log(arr1); //[1, 2]

console.log(arr2); //[3, 2]

此时,arr2的修改并没有影响到arr1,我们把arr1改成二维数组再来看看:

var arr1 = [1, 2, [3, 4]], arr2 = arr1.slice();

console.log(arr1); //[1, 2, [3, 4]]

console.log(arr2); //[1, 2, [3, 4]]

arr2[2][1] = 5;

console.log(arr1); //[1, 2, [3, 5]]

console.log(arr2); //[1, 2, [3, 5]]

咦,arr2有改变了arr1,看来slice()只能实现一维数组的深拷贝。

具备同等特性的还有:concatArray.from()

Object

1、Object.assign()

var obj1 = {x: 1, y: 2}, obj2 = Object.assign({}, obj1);

console.log(obj1) //{x: 1, y: 2}

console.log(obj2) //{x: 1, y: 2}

obj2.x = 2; //修改obj2.x

console.log(obj1) //{x: 1, y: 2}

console.log(obj2) //{x: 2, y: 2}

var obj1 = {

x: 1,

y: {

m: 1

}

};

var obj2 = Object.assign({}, obj1);

console.log(obj1) //{x: 1, y: {m: 1}}

console.log(obj2) //{x: 1, y: {m: 1}}

obj2.y.m = 2; //修改obj2.y.m

console.log(obj1) //{x: 1, y: {m: 2}}

console.log(obj2) //{x: 2, y: {m: 2}}

经测试,Object.assign()也只能实现一维对象的深拷贝

2、JSON.parse(JSON.stringify(obj))

var obj1 = {

x: 1,

y: {

m: 1

}

};

var obj2 = JSON.parse(JSON.stringify(obj1));

console.log(obj1) //{x: 1, y: {m: 1}}

console.log(obj2) //{x: 1, y: {m: 1}}

obj2.y.m = 2; //修改obj2.y.m

console.log(obj1) //{x: 1, y: {m: 1}}

console.log(obj2) //{x: 1, y: {m: 2}}

JSON.parse(JSON.stringify(obj))看起来在实现深拷贝上做的不错,不过 MDN 文档的描述有句话写的很清楚:

undefined、任意的函数以及 symbol 值,在序列化过程中会被忽略(出现在非数组对象的属性值中时)或者被转换成 null(出现在数组中时)。

我们再来把 obj1 改造下:

var obj1 = {

x: 1,

y: undefined,

z: function add(z1, z2) {

return z1 + z2

},

a: Symbol(‘foo’)

};

var obj2 = JSON.parse(JSON.stringify(obj1));

console.log(obj1); //{x: 1, y: undefined, z: f, a: Symbol(foo)}

console.log(JSON.stringify(obj1)); //{“x”: 1}

console.log(obj2) //{x: 1}

发现,在将 obj1 进行 JSON.stringify() 序列化的过程中,y、z、a都被忽略了,也就验证了 MDN 文档的描述,既然这样,那 JSON.parse(JSON.stringify(obj)) 的使用也是有局限性的,不能深拷贝含有undefined、function、symbol值的对象,不过 JSON.parse(JSON.stringify(obj)) 简单粗暴,已经满足 90% 的使用场景了。

经过验证,我们发现 JS 提供的自有方法并不能彻底解决 Array、Object 的深拷贝问题。只能祭出大杀器:递归

function deepCopy(obj) {

// 创建一个新对象

let result = {}

let keys = Object.keys(obj),

key = null,

temp = null;

for (let i = 0; i < keys.length; i++) {

key = keys[i];

temp = obj[key];

// 如果字段的值也是一个对象则递归操作

if (temp && typeof temp === ‘object’) {

result[key] = deepCopy(temp);

} else {

// 否则直接赋值给新对象

result[key] = temp;

}

}

return result;

}

var obj1 = {

x: {

m: 1

},

y: undefined,

z: function add(z1, z2) {

return z1 + z2

},

a: Symbol(“foo”)

};

var obj2 = deepCopy(obj1);

obj2.x.m = 2;

console.log(obj1); //{x: {m: 1}, y: undefined, z: ƒ, a: Symbol(foo)}

console.log(obj2); //{x: {m: 2}, y: undefined, z: ƒ, a: Symbol(foo)}

可以看到,递归完美的解决了前面遗留的所有问题,我们也可以用第三方库: jquery$.extendlodash_.cloneDeep 来解决深拷贝。上面虽然使用 Object 验证,但对于 Array 也同样使用,因为 Array 也是特殊的 Object。

但是,还有一个非常特殊的场景:

循环引用拷贝

var obj1 = {

x: 1,

y: 2

};

obj1.z = obj1;

var obj2 = deepCopy(obj1);

此时如果调用刚才的 deepCopy 函数的话,会陷入一个循环的递归过程,从而导致爆栈。 jquery$.extend 也没有解决。解决这个问题也非常简单,只需要判断一个对象的字段是否引用了这个对象或这个对象的任意父级即可,修改一下源代码:

function deepCopy(obj, parent = null) {

// 创建一个新对象

let result = {};

let keys = Object.keys(obj),

key = null,

temp= null,

_parent = parent;

// 该字段有父级则需要追溯该字段的父级

while (_parent) {

// 如果该字段引用了它的父级则为循环引用

if (_parent.originalParent === obj) {

// 循环引用直接返回同级的新对象

return _parent.currentParent;

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

最后

前端校招精编面试解析大全点击这里获取完整版pdf查看

,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!**

[外链图片转存中…(img-3NOFlnRx-1713268933519)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:前端)

最后

前端校招精编面试解析大全点击这里获取完整版pdf查看

  • 29
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值