✊不积跬步,无以至千里;不积小流,无以成江海
什么是深拷贝
不是浅拷贝的都是深拷贝。
将一个对象的a属性集合,完全拷贝成b,使a/b完全一致,且ab的属性之间没有任何的交集,引用b的属性不会指向a,就是深拷贝。
/////
浅拷贝是指只复制对象的引用,而不是复制对象本身。也就是说,原对象和拷贝对象指向同一块内存空间。
方法一,用 JSON:
思路
用json方法可以实现深拷贝,但是有如下问题:
-
不支持 Date、正则、undefined、函数等数据
-
不支持引用(即环状结构)
实现
// 反序列化 序列化
const b = JSON.parse(JSON.stringify(a))
方法二,用递归:
思路
自己调用自己。(第2行和第30行)
- 先判断数据的类型,属于八种中的哪一个,由于对象最特殊,则分为对象 & 其他类型
- 在对象中,分为函数,数组,日期和正则。
- 在函数中,需要判断是普通函数还是箭头函数
- 如果该函数有protopype,那么它就是普通函数,我们需要返回一个结果(结果需提前声明),能够复制a的所有功能。则实现该功能需要apply a传入的所有参数,并返回。
- 那么对于函数的所有属性,对a进行遍历并复制给deepClone函数
- 如果该函数为箭头函数,那么将这个函数传入的所有属性都传给a
- 在对象中,如果该类型属于数组,则将return赋值给数组
- 在对象中,如果该类型属于日期,则将return赋值给newData,newData - 0 是日期序列化之后的结果
- 在对象中,如果该类型属于正则,则将return赋值给newRegExp,newRegExp 接受两个参数,文本source和flags
- 则在对象中,剩余的情况,就默认为是普通属性直接拷贝。
- 设置一个a去测试一下,发现如果a.self时(自引用)会出错(需要解决环),为了解决这个问题,我们可以给a添加一个“记忆功能”,如果a第二次次访问的地址之前已经访问过了,就直接导到第一次的地址。
- 那么这个记忆功能需要一个map来去解决,用cache命名。因为map的key是对象,所以用map属性。(obj的key是string / symbol)
- 如果我们get一下cache发现有a,我们就返回对应被我们拷贝的东西。并用cache.set将缓存a和result做对应
- 当我们拷贝时,存在一种情况,当它的有些属性是继承自其他函数时,我们不应该拷贝它。所以在for循环遍历里面,加上限定条件,当key为自身属性时,我们才拷贝它。
实现
const cache = new Map()
const deepClone = (a) => {
if(cache.get(a)){
return cache.get(a)
}
if(a instanceof Object) {
let result
if(a instanceof Function) {
if(a.prototype) { // 有 prototype 就是普通函数
result = function(){ return a.apply(this, arguments) }
} else {
result = (...args) => { return a.call(undefined, ...args) }
}
} else if(a instanceof Array) {
result = []
} else if(a instanceof Date) {
result = new Date(a - 0)
} else if(a instanceof RegExp) {
result = new RegExp(a.source, a.flags)
} else {
result = {}
}
cache.set(a, result)
for(let key in a) {
if(a.hasOwnProperty(key)){
result[key] = deepClone(a[key])
}}
}
else{
// number symbol string bool null undefine bigint
return a
}
}
const a = {
number:1, bool:false, str: 'hi', empty1: undefined, empty2: null,
array: [{name: 'frank', age: 18}, {name: 'jacky', age: 19}],
date: new Date(2000,0,1,20,30,0),
regex: /\.(j|t)sx/i,
obj: { name:'frank', age: 18},
f1: (a, b) => a + b,
f2: function(a, b) { return a + b }
}
a.self = a
const b = deepClone(a)
b.self === b // true
b.self = 'hi'
a.self !== 'hi' //true