总结:深拷贝和浅拷贝 考察的实际上是对内存的理解 基本类型数据存在栈内存中,而对象,数组实际的存储位置是在堆内存中,但是它们的指针存在栈内存中,所以直接拷贝基本类型数据相当于在栈内存中新建一块内存进行存储,而拷贝对象、数组实际上是对其指针的指向进行了改变,相当于在栈内存中新建一块内存存放指针,而拷贝过来的数据和原数据都指向同一块堆内存的地址,所以会出现数据互相影响的问题。
第一种 可以使用简单的方法JSON
const person = {
name:'jack',
age:'11'
}
const copyPerson = JSON.parse(JSON.stringify(person))
修改person内name属性:
person.name = 'che'
console.log(person) // {name: "che", age: "11"}
console.log(copyPerson) // {name: "jack", age: "11"}
可以看到从拷贝过来的copyPerson不再受person的影响
但是JSON的方法会存在一个弊端 就是无法拷贝类型为 function undefined 和es6新增的sysbol 他们会在拷贝过程中丢失。
第二种 递归实现
function deepCopy(obj){
// 定义一个新的返回值变量
let newObj = null
// 判断下入参类型 只有存在堆内存中的数据类型 才会使用
// 深拷贝,基本类型直接赋值即可 同时对null进行处理 null循
// 环会报错
if(obj instanceof Object && obj !== null){
// 确定返回值类型 使用三元运算符
newObj = Array.isArray(obj) ? [] : {}
// 开始循环
for(let i in obj){
// 反复调用本身 直到所有数据都处理完毕
newObj[i] = deepCopy(obj[i])
}
}else{
newObj = obj
}
return newObj
}
//使用时直接调用即可
const person = {
name:'jack',
age:'11'
}
const newPerson= deepCopy(person)
考虑递归中存在循环引用问题
// 使用weakmap解决循环引用
// 优点:
// 1 .WeakMap来记录对象是否被克隆,主要考虑一下三点。
// 2 .WeakMap对象是key=>value形式,不会重复记录
// 3 .WeakMap是弱引用,如果不在使用,空间会直接释放
function deepCopy (obj, hash= new WeakMap()) {
// 不是对象(普通值类型/function),null,undefined,正则,Date都会直接返回
if(obj == null || typeof obj != 'object') {
return obj
}
if(obj instanceof RegExp ) {
return new RegExp(obj)
}
if( obj instanceof Date) {
return new Date(obj)
}
// 判断是否循环引用的(判断属性是不是存在了)
if(hash.get(obj)) return hash.get(obj)
// 判断返回类型
let cloneObj = new obj.constructor()
// 存obj
hash.set(obj, cloneObj)
for(let key in obj) {
// in 循环会遍历原型链的,所以需要判断是否是当前对象的属性
if(Object.hasOwn(obj,key)) {
cloneObj[key] = deepCopy(obj[key], hash)
}
}
return cloneObj
}