关于手写实现深浅拷贝,我在网上看了很多,可以说是各有各的问题,最后还是一个博主说的对,手写图个乐,真要用到深拷贝,还得是lodash。但是没办法啊,只能为了写而写了 - -(综合了一下网上找到的几个版本)
一、什么是深浅拷贝
咱们行动有问题,但是思想不能有问题啊。那么什么是深浅拷贝的思想呢?
浅拷贝和深拷贝都是创建一份数据的拷贝。JS 分为基本数据类型和引用数据类型,对于基本数据类型的拷贝,并没有深浅拷贝的区别,如果必须要按照深浅拷贝的概念理解的话,对于基本数据类型的复制可以理解为按值深拷贝。我们讨论的深浅拷贝都只针对引用数据类型。浅拷贝和深拷贝都复制了值和地址,都是为了解决引用类型赋值后互相影响的问题。但是浅拷贝只进行一层复制,深层次的引用类型还是共享内存地址,原对象和拷贝对象还是会互相影响。深拷贝就是无限层级拷贝,深拷贝后的原对象不会和拷贝对象互相影响。
二、原生方式实现和递归方式实现
怎么说,我不仅实现,我还要用两种方式!卷,狠狠的卷
原生方式:
原生方法实现深拷贝,主要是使用JSON.parse()
与JSON.stringify()
,首先将对象序列化为JSON
字符串,再将JSON
字符串反序列化为对象,使用这种方式效率比较高,但是会有一些问题,对于循环引用的对象无法实现深拷贝,对于被拷贝的对象,如果对象中有属性为Date
对象,此种方式深拷贝会将时间对象转化为字符串;如果对象中有属性为RegExp
对象、Error
对象,此种方式深拷贝会得到一个空对象;如果对象中有属性为function
对象、undefined
、Symbol
值,此种方式深拷贝会忽略这些值;如果对象中有属性为NaN
、Infinity
、-Infinity
,此种方式深拷贝会将结果转为null
。(我知道你看这一大段文字很急,但是你先别急)
/** 原生方法 */
// 浅拷贝
function shallowCopy(target,orign){
return Object.assign(target,orign)
}
// 深拷贝
function deepCopy(target,orign){
let deepCopyResult = JSON.parse(JSON.stringify(orign))
return Object.assign(target,deepCopyResult)
}
递归方式:
对于浅拷贝,只需要处理被拷贝对象的所有的可枚举属性进行赋值即可。对于深拷贝,需要将基本数据类型进行赋值,然后对对象属性进行递归处理。
/** 递归实现 */
// 浅拷贝
function shallowClone(target,orign){
for(let item in orign){
target[item] = orign[item]
}
return target
}
// 深拷贝
function deepClone(target,orign){
for(let item in orign){
if(orign[item]&&typeof orign[itme]==='object'){
if(Object.prototype.toString.call(orign[item])==='[Object Object]'){
target[item] = deepClone({},orign[item])
}else if(orign[item] instanceof Array){
target[item] = deepClone({},orign[item])
}else if(orign[item] instanceof Date){
target[item] = new Date(orign[item])
}else if(orign[item instanceof RegExp]){
target[item] = new RegExp(orign[item].source,orign[item].flags)
}else{
target[item] = orign[item]
}
}else{
target[item = orign[item]]
}
}
return target
}