学习这个概念花了一点时间,后来面试也被要求手写过,因此在这里记录一下自己的理解。
首先,理解这个概念的前提:深浅拷贝是针对引用类型(array、object)的讨论。而对于基本类型(number、boolean、string、null、undefined),他们的深浅拷贝并无意义,因为他们没有嵌套属性。
深拷贝的定义
MDN对深拷贝的定义:
- 它们不是一个对象(o1 !== o2)
- o1和o2的属性具有相同的名称且顺序相同
- 它们的属性值是彼此的深拷贝
- 它们的原型链深结构等价的
即:假设o2是o1的深拷贝对象,它们不能共享地址,o2需要像新开一个堆来存放数据。同时,o1和o2所有属性的值和数据类型必须一样。达成以上要求后,修改o2的任意属性都不会影响o1。
深拷贝的代码实现
假设要对以下对象进行深拷贝:
let obj1 = {
id: 1,
name: 'fox',
Characteristics:{
role: 'anti-hero',
color: 'orange'
}
}
使用lodash工具包里的cloneDeep函数就可以直接进行深拷贝,详细使用请见它的官方文档。 不过,为了深拷贝而特地安装一个lodash工具包太浪费资源了,更推荐使用2022年JS推出的原生深拷贝API - structuredClone(),直接使用一步到位,兼容性问题也被解决得很好:MDN上有它的详细介绍和使用方法。
但是!为了面试!最好还是要学会手写循环递归实现深拷贝!
循环递归实现
function deepClone(obj){
//如果obj为空,不是object或array类型则不进行深拷贝
if(obj === null || typeof obj !== "object") return obj;
let objClone = obj instanceof Array ? [] : {};
for(key in obj){ //开始循环拷贝obj里的每个属性
if(obj.hasOwnProperty(key)){
if(obj[key] && typeof obj[key] === "object"){ //判断是否是object或array类型
objClone[key] = deepClone(obj[key]); //是则递归复制
}
else{
objClone[key] = obj[key]; //不是则直接赋值
}
}
}
return objClone;
}
//测试
let obj2 = deepClone(obj1);
obj2.id = 2;
obj2.Characteristics.role = 'hero';
console.log(obj2); //id被改成2,嵌套属性role被改成hero
console.log(obj1); //id仍然是1,role仍然是anti-hero
感谢观看,有问题可以在评论区友好讨论~