首先我们要知道,js有两大类数据类型:
1.值类型(基本类型):字符串(String)、数字(Number)、布尔(Boolean)、空(Null)、未定义(Undefined)、Symbol
2.引用数据类型(对象类型):对象(Object)、数组(Array)、函数(Function),还有两个特殊的对象:正则(RegExp)和日期(Date)。
由于值类型数据较简单,所以创建时候直接储存在栈内存中,在拷贝的时候,会新生成一份储存在栈中,两者互不影响。
而引用数据类型,由于数据结构较复杂,所以创建时候一般都是储存在堆内存中,然后会在栈中生成一份引用(里面保存的是该引用类型在堆内存中的地址,类似c语言的指针)。在拷贝的时候,不会重新在堆内存中生成一份数据,而是直接在栈内存中新生成一份引用指向原本的那个堆内存地址。所以浅拷贝的话,只是拷贝了一份地址,指向了同一个对象,并没有新生成一个对象。
如果我们想要得到原对象的一份真正的独立的复制体,我们就需要对其进行手动深拷贝,即遍历该对象的所有属性,并将其添加到那个复制体对象上面去。
这时候我们会遇到一个问题,如果对象上面的属性是另一个对象,这时候如果我们进行普通普通拷贝,就会遇到和上面同样的问题,所以我们需要对这个手动的深拷贝函数进行循环调用。
function deepClone(obj = {}) {
if (typeof obj != 'object' || obj == null) {
//如果传入的obj不是一个对象,那么就不需要进行深拷贝,值类型直接赋值就可以了
return obj
}
//let newObj
//判断obj是数组还是对象,以确认newObj的类型
//obj instanceof Object ? newObj = {} : newObj = []
//优化版
let newObj = new obj.constructor
//用for in 遍历obj的属性
for(let index in obj){
//只拷贝对象本身拥有的属性,不拷贝原型链上面的属性
if(obj.hasOwnProperty(index)){
//循环调用赋值,因为有可能碰到obj的某个属性同样也是一个对象的情况
newObj[index]=deepClone(obj[index])
}
}
return newObj
}
上面是面试时候一般需要写的深克隆,而实际开发环境中,一般使用
JSON.parse(JSON.stringify(obj))
这种方式的弊端就是无法正确克隆函数、正则、日期等,但是一般开发的话只需要克隆数组、对象、基本值
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)