起因
今天心血来潮,想着自己实现一下对象深拷贝。在此之前,有了解过实现深拷贝的方法,其中印象较为深刻的方法有两种:
- 递归拷贝
- JSON.stringify和JSON.parse
其中第2种方法在对象中存在function或RegExp时会出现问题,且是js已有的方法,因此就打算自己手写一下递归实现深拷贝的方法,然后比较比较自己的实现方法与网上大佬的实现方法的区别,分析自己代码所存在的问题。
自己的深拷贝实现方法
我的实现思路:
- 判断参数类型
- 参数为数组
- 创建空数组
- 遍历参数并判断元素类型
- 元素为数字则push空数组
- 否则递归
- 参数为对象
- 创建空对象
- 遍历对象并判断对象类型
- 元素为非数组或非对象则为空对象新增属性
- 否则递归
具体代码:
function deepCopy(obj){
if(obj.constructor === Array) {
let result = []
for(let item of obj){
if(item.constructor === Array){
result.push(deepCopy(item))
}else{
result.push(item)
}
}
return result
}else{
const result = {}
for(let item in obj){
if(obj[item] instanceof Array){
result[item] = deepCopy(obj[item])
} else if(typeof obj[item] === "object") {
result[item] = deepCopy(obj[item])
}else{
result[item] = obj[item]
}
}
return result
}
}
存在的问题:当数组中的元素为对象时,会出现问题
出现的原因:实现时没有考虑到数组中的元素可以为对象
网上大佬的实现方法
function deepClone(obj){
let objClone = Array.isArray(obj)?[]:{};
if(obj && typeof obj==="object"){
for(key in obj){
if(obj.hasOwnProperty(key)){
//判断obj子元素是否为对象,如果是,递归复制
if(obj[key]&&typeof obj[key] ==="object"){
objClone[key] = deepClone(obj[key]);
}else{
//如果不是,简单复制
objClone[key] = obj[key];
}
}
}
}
return objClone;
}
我的实现方法存在的问题
- 我的方法没有正确实现深拷贝功能
- 判断参数类型并创建初始返回值使用三元运算符判断更为简便
- 利用typeof判断参数类型时,Array与Object都会被判断为object,当判定为true时进行递归,当判定为false时为返回值新增属性(或添加元素)
注释 :由于obj与arr都是以obj[key]的形式进行操作的,因此在判断条件为true时可以直接进行递归,无需再判断参数是否为Array
其他的实现深拷贝的方法
- 函数库lodash的_.cloneDeep方法
- 通过JQuery的extend方法实现深拷贝
由于我个人的工作使用的框架是VUE,因此大概率不会使用这种方法进行深拷贝