javascript深拷贝

107 阅读2分钟

常用深拷贝与浅拷贝

深拷贝和浅拷贝的基本的理解为就是复制引用数据类型的时候其实不是真正复制了一个对象而是复制了引用数据类型存放在栈内存里面的地址,可能对引用数据类型和堆内存不了解,下面我们来讲下

数据类型分为基本数据类型和引用数据类型
基本数据类型有:number,string,boolean,null,undefined,symbol 和未来要新增的 BigInt 数据类型

引用数据类型有:数组,对象,函数

内存分为 栈内存 和 堆内存

基本数据类型名称和值都存在栈内存中,复制一个基本数据类型的数据会重新开辟一个例如 栈内存.jpg

栈内存2.jpg

引用数据类型名称和值都存在堆内存中,但引用地址存放在栈内存中

堆内存.jpg

当 b=a 进行拷贝时,其实复制的是 a 的引用地址,而并非堆里面的值

堆内存2.jpg

所以浅拷贝只是简单的复制了引用数据类型存放在栈内存中的地址并没有重新在堆内存中开辟一块区域存一个新的引用类型数据

我们开发中常用的拷贝有这些

let obj2={...obj} 解构赋值

Object.assign({},obj) Object 对象合并

JSON.parse(JSON.stringfy(obj))

以上这些拷贝有些是深拷贝有些是浅拷贝,让我们来验证下

let obj = {
    name:"张三",
    arr:[1,2,3,4],
    getName:function(){
        console.log(this.name)
    },
    info:{
        id:10,
        sex:"男"
    },
    reg:new RegExp("b"),
    date:new Date()
}

1. let obj2={...obj}解构赋值(浅拷贝)

解构赋值.png

这样看起来是深拷贝但我们修改下深层极的试试

解构赋值2.png

修改了 obj 里面的 info 中的属性 obj2 也会跟着修改

2. Object.assign({},obj) Object 对象合并(浅拷贝)

Object.assign.png

这样看起来也是深拷贝但我们修改下深层级的试试

Object.assign2.png

修改了 obj 里面的 info 中的属性 obj2 也会跟着修改

3. JSON.parse(JSON.stringfy(obj)) JSON 复制粘贴 (深拷贝但有问题)

JSON.parse(JSON.stringify()).png

可以看到修改 obj.name 和 obj.info.sex 后 obj2 里面不会随着改变,但 Date 数据复制后成了字符串,RegExp 数据复制后变为空对象({})

没有很好的支持深拷贝的方法那我们自己写个试试

function deepClone(obj){
    if(obj == null){
        return obj;
    }
    if(typeof obj !=="object"){
        return obj;
    }
    if(obj instanceof Date){
        return new Date(obj)
    }
    if(obj instanceof RegExp){
        return new RegExp(obj)
    }
    let cloneObj=new obj.constructor();
    for(let key in obj){
       if(obj.hasOwnProperty(key)){
           cloneObj[key]=deepClone(obj[key])
       }
    }
    return cloneObj
}

deepclone.png