【校招VIP】JS实现深拷贝的三种方式

08月24日 收藏 0 评论 0 前端开发

【校招VIP】JS实现深拷贝的三种方式

转载声明:文章来源:https://blog.csdn.net/weixin_45452083/article/details/121852054

深浅拷贝是面试中经常会被问到的问题,这会帮大家整理一下,浅拷贝不写了,这次主要是深拷贝。

看段代码

let obj = {
a:1,
b:{
c: 1
},
}

let copyObj = obj
copyObj.a = 2
console.log(obj, copyObj)

这就浅拷贝了

1.JSON.parse(JSON.stringify(obj))

let copyObj = JSON.parse(JSON.stringify(obj))
copyObj.a = 2
console.log(obj, copyObj)

这样就成功了。

面试官:这种实现方案有什么问题吗?

答:该方法不能解决属性为函数,undefined,循环引用的的情况

上代码,看效果

let obj = {
a:undefined,
b:{
c: function() {
console.log(1)
},
d: null,
e: new Date(),
f: new RegExp('\\w+'),
g: NaN
},
}

let copyObj = JSON.parse(JSON.stringify(obj))
console.log(obj, copyObj)

1.原对象中的a、c不见了,undefined、function类型的key会丢失

2.e时间对象,会变成字符串形式

3.RegExp定义的属性会变成 {}

4.NaN 类型会变成 null

还有一个问题: 循环引用

let obj = {
a:1,
}
obj.c = obj
let copyObj = JSON.parse(JSON.stringify(obj))
console.log(obj, copyObj)

5.无法处理循环引用的问题

结论:这种拷贝方式局限性比较大,但是在日常开发中一般只是拷贝基本的数据类型,个人在开发中用的还是比较多

2.递归

一般我们会这样写

function copy(obj){
let newobj = null;
if(typeof(obj) == 'object' && obj !== null){
newobj = obj instanceof Array? [] : {};
for(var i in obj){
newobj[i] = copy(obj[i])
}
}else{
newobj = obj
}
return newobj;
}

面试官:递归实现有什么问题吗?

还是循环引用的问题

let obj = {
a:1,
}
obj.a = obj
let copyObj = copy(obj)
console.log(obj, copyObj)

还是会报错

解决:用 WeakMap() 或者Map()记录下对象中的所有对象,并与新创建的对象一一对应,即记录引用关系

let map = new Map(); // WeakMap
function copy(obj){
let newobj = null;
if(typeof(obj) == 'object' && obj !== null){
if (map.get(obj)) {
newobj = map.get(obj) // 如果不想循环打印 可以设置为null
} else {
newobj = obj instanceof Array? [] : {};
map.set(obj, newobj)
for(var i in obj){
newobj[i] = copy(obj[i])
}
}

}else{
newobj = obj
}
return newobj;
}
obj.b = obj
let copyObj = copy(obj)
console.log(obj, copyObj)

注意:如果遇到时间对象,正则等类型,需要通过new关键字去创建

3.jQuery.extend() 函数

jQuery.extend() 函数用于将一个或多个对象的内容合并到目标对象。

第一个参数是boolean类型,表示深浅拷贝,true表示深拷贝,false表示浅拷贝。只有两个参数,那么就把jQuery作为target,把第二个参数的字段赋给target,然后返回target。多于两个参数,把第二个参数作为target,然后把后面的参数的字段赋给target,最后面返回target.

let obj = {
a:1,
b: {
c:2
}
}
let copyObj = {}
$.extend(true,copyObj, obj);
copyObj.b = 3
console.log(obj, copyObj)

问题:当然如果两拷贝对象中有相同的属性名时,后者的值也会覆盖前者的值,就像这样:

let obj = {
a:1,
b: {
c:2
}
}
let obj2 = {
a:2,
d:4
}

$.extend(true,obj, obj2);
console.log(obj, obj2)

PS:jQuery这个框架现在使用量比较小,个人不做深入研究了




C 0条回复 评论

帖子还没人回复快来抢沙发