👉🏼了解深拷贝的之前先了解一下数据类型
JavaScript中存在两大数据类型:
- 基本类型 Number String null Undefined Boolean symbol
- 引用类型 array object function
基本类型数据保存在在栈内存中
引用类型数据保存在堆内存中,引用数据类型的变量是一个指向堆内存中实际对象的引用,存在栈中
深拷贝 && 浅拷贝
-
浅拷贝是创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。
-
深拷贝是将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象。
👇🏼借助这张图了解一下深拷贝和浅拷贝的区别
💁🏼♀️下面来看看怎么一步一步实现深拷贝函数吧:
1.普通赋值对象的过程
const oldObj = {
name:'哈默',
age:20,
colors:['orange','green','blue'],
friend:{
name:'小夏'
}
}
const newObj = oldObj;
newObj.name = '小野';
console.log('oldObj',oldObj);
console.log('newObj',newObj);
可以看出原对象的数据被改变,这是一次浅拷贝的过程
2.🙇🏼♀️深拷贝函数的初成型
const oldObj = {
name:'哈默',
age:20,
colors:['orange','green','blue'],
friend:{
name:'小夏'
}
}
function deepClone(obj = {}){
// 如果是基本数据类型
if(typeof obj !== 'object' || obj == null){
return obj;
}
let result;
// 拷贝过程1.定义格式
// 两种情况,传入的是数组,传入的是对象
if(obj instanceof Array)
result = [];
else
result = {};
// 2.循环拷贝属性
for(let key in obj){
// 核心,属性拷贝
result[key] = obj [key];
}
return result;
}
const newObj2 = deepClone(oldObj);
newObj2.name = '小野';
console.log('oldObj',oldObj);
console.log('newObj2',newObj2);
以上的代码只是实现第一层是深拷贝 ,改变name属性时会得到如图结果,那么如果将oldObj中的friend对象中的name属性改变会发生什么呢?
如图,如果使用上面的代码,我们的friend对象的name属性改变,原对象也改变。说明,此时的深拷贝并没有完善,需要再完善完成多层深拷贝,那么如何做到呢?
我们可以利用递归的方法完成多层的深拷贝,仔细阅读如下代码,我们的小小改动就可以是实现多层深拷贝啦~
2.🙇🏼♀️深拷贝函数实现多层深拷贝
function deepClone(obj){
// 如果是基本数据类型
if(typeof obj !== 'object' || obj == null){
return obj;
}
let result;
// 拷贝过程1.定义格式
// 两种情况,传入的是数组,传入的是对象
if(obj instanceof Array)
result = [];
else
result = {};
// 2.循环拷贝属性
for(let key in obj){
// 核心,属性拷贝
//利用递归多层拷贝
result[key] = deepClone(obj[key]);
}
return result;
}
const newObj2 = deepClone(oldObj);
newObj2.friend.name = '小李';
console.log('oldObj',oldObj);
console.log('newObj2',newObj2);
此时可见代码中利用了递归的方式,将实现了多层深度拷贝,此时的friend对象里的name值被改变,原对象中的数据却不变如图:
你以为这就大功告成了吗,不不不,我们还要注意,深拷贝我们只拷贝对象的属性,对象的原型链上的不可以被拷贝哦,所以要多加一层判断,防止原型链被查找并拷贝。
我们使用的是hasOwnProperty方法。
hasOwnProperty表示是否有自己的属性。这个方法会查找一个对象是否有某个属性,但是不会去查找它的原型链。
3.🙇🏼♀️深拷贝函数完成~
function deepClone(obj){
// 如果是基本数据类型
if(typeof obj !== 'object' || obj == null){
return obj;
}
let result;
// 拷贝过程
// 1.定义格式
// 两种情况,传入的是数组,传入的是对象
if(obj instanceof Array)
result = [];
else
result = {};
// 2.循环拷贝属性
for(let key in obj){
// 3.防止原型属性被拷贝
if(obj.hasOwnProperty(key)){
// 核心,属性拷贝
result[key] = deepClone(obj[key]);
}
}
return result;
}
好啦,深拷贝我们完成了~~
🤓是不是很简单,接下来我们来总结一下防止面试时紧张忘记了。
总结】深拷贝的实现有三个重要步骤:
1.首先判断传入的数据类型
2.拷贝的过程中要判断数据格式(用来保存返回数据的)
3.通过循环 for...in...(遍历原型链)进行拷贝,拷贝的过程中不要忘记避免拷贝原型链上的属性