🌈个人主页: 鑫宝Code
🔥热门专栏: 闲话杂谈| 炫酷HTML | JavaScript基础
💫个人格言: "如无必要,勿增实体"
上次讲了浅拷贝,这次我们来讲深拷贝。有一说一,深拷贝也算是面试时非常常见的题目了。🐶
首先为什么需要深拷贝,因为浅拷贝无法满足我们对原始数据完整、独立复制的需求。我们希望修改新对象不会影响原对象。
这里引用
ConardLi
大佬的理解
创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。
所以如果其中一个对象改变了这个地址,就会影响到另一个对象。
将一个对象从内存中完整的拷贝一份出来
遥记当年,我当时还是大三的时候,背了一周的面经就跑去字节面试实习生了。面试官就让我手撕深拷贝。
我当时才20刚出头,前端面经也才抱起来背了不到一周。这种题目我写的来得?
跟面试官面面相觑了半天,突然灵机一动,JSON.parse(JSON.stringfy())大法一定可以。
我当时非常开心的说出了这个答案, 面试官当时好像有点尬住了,嘴角流露出一股察摸不到的笑容。
但可能由于接受过专业的训练,也只在那短短的时间内便消失不见。🐶
JSON.parse(JSON.stringify())
,首先使用利用JSON.stringify
将对象转成JSON
字符串。 再用JSON.parse
把字符串解析成对象,一去一来,新的对象产生了,而且对象会开辟新的栈,实现深拷贝。
const a = {
name: '张三',
score:{
math: 100
}
}
const b = JSON.parse(JSON.stringify(a));
// 改变b中的对象的值
b.score.math = 60;
console.log('a的值',a);
console.log('b的值',b);
/**
* 输出的结果如下
* a的值 { name: '张三', score: { math: 100 } }
* b的值 { name: '张三', score: { math: 60 } }
*/
记个TODO:下次写文章详细分析下
JSON.stringify
的缺点。
undefined
的值Symol
会丢失等续借上文,面试官笑了笑,说
JSON.parse(JSON.stringify())
这个方式有如上几个缺点,你能不能换个更好的方式将这个问题解决呢?这又一次的让我陷入了思索,又开始了与面试官的面面相觑😅。突然我想起了以前用的Lodash,其中有一个NB的方法。
cloneDeep
,当时我洋洋得意,心想lodash
库的方法,总不可能还有缺点吧?此时,面试官的表情稍稍有点微妙,我的第六感告诉我,我好像答错了,不过我认为我回答的没问题呀。
晌久,面试官叹了口气说,我是让你手撕,手撕懂吗?
_.cloneDeep
是lodash
库提供的深拷贝的方法,非常实用,建议背诵😂。
import * as _ from "lodash";
const a = {
name: "张三",
score: {
math: 100,
},
};
const b = _.cloneDeep(a);
暂无,🐮的lodash库,🐮的cloneDeep函数。
诶,还是得手撕呀,来吧来吧,还是得给面试官露一手的😜
多年面试经验告诉我,一般写出这个版本,几乎都让过了,顶多在回答一下循环引用问题如何解决。一般不太会让写一个比较完美的深拷贝的。🐶
Array
和Object
代码如下:
function deepClone(target) {
if (typeof target === "object") {
let cloneTarget = Array.isArray(target) ? [] : {};
for (const key in target) {
cloneTarget[key] = deepClone(target[key]);
}
return cloneTarget;
} else {
return target;
}
}
const a = {
name: "张三",
score: {
math: 100,
},
};
const b = deepClone(a);
/** 输出的b与a一样 **/
但是这样实现会有若干个问题:
Date
和RegExp
等对象无法拷贝之所以用
weakMap
,是因为weakMap
的键是弱引用,可以在任何时刻被回收。如果想了解更清楚进阶深拷贝的原理,可以参阅 如何写出一个惊艳面试官的深拷贝?
function deepClone(target, hash = new WeakMap()) {
if (target === null) return null;
if (typeof target !== "object") return target;
if (target instanceof Date) return new Date(target);
if (target instanceof RegExp) return new RegExp(target);
// 如果hash里有值,立马返回
if (hash.has(target)) return hash.get(target);
const cloneTarget = Array.isArray(target) ? [] : {};
hash.set(target,cloneTarget);
if (typeof target === "object") {
for (const key in target) {
cloneTarget[key] = deepClone(target[key],hash);
}
return cloneTarget;
} else {
return target;
}
}
const a = {
name: "张三",
score: {
math: 100,
},
date: new Date(),
regex: /^\d{3,4}-\d{5,8}$/,
};
a.child = a;
const b = deepClone(a);
运行结果如下: