随手撸个深拷贝deepClone

526 阅读2分钟

一:Why deepClone?

说到深拷贝(拷贝基本适用于引用类型的拷贝),就不得不说JS数据类型、浅拷贝、栈/堆。

  1. JS数据类型
1:基本类型
 StringNumberBooleanNullUndefined.
2:引用类型
 ObjectArryFunction
  1. 栈/堆
1:栈(Stack)
内存中开辟地址,直接赋值,占据固定大小的空间。
2:堆(Heap)
存放对象数值,在栈内存中保存一个指针的地址,此地址指向堆中保存的数值
  1. 浅拷贝

浅拷贝是直接引用在栈中的指针的地址,此地址指向真正保存在堆中的数值。故任何一方只要改变对象的数值。双方数值都会改变

  1. 深拷贝

重新在堆中生成新的数值,栈中生成新的指针地址。即使改变拷贝之后对象的属性值,原始对象值不会改变,没有影响。

let obj1={
    age:17,
    sex:"woman",
    address:{
        city:'shenzhen'
    },
    arr:[1997,"百度",2000,"alibaba"]
}
let obj2=obj1;
console.log("obj2:",obj2)
obj2.age=34;
console.log("改变obj2的age值之后","obj1:",obj1);
console.log("改变obj2的age值之后","obj2:",obj2);

shallowClone.png

二:How deepClone?

  1. ES5结构赋值(局限性:只适用一维数据)
let obj1={
    a:11,b:22
}
let obj2={...obj1}
obj2.a='obj2'
console.log('使用ES5解构改变obj2之后-obj1:',obj1)
console.log('使用ES5解构改变obj2之后-obj2:',obj2)
let ary1=[1,2]
let ary2=[...ary1]
ary2.push('ary2')
console.log('使用ES5解构改变ary2之后-ary1:',ary1)
console.log('使用ES5解构改变ary2之后-ary2:',ary2)

解构.jpg

  1. JSON对象(局限性:对于function不生效,请自行验证)
let obj1={
  a:11,b:22
}
let obj2=JSON.parse(JSON.stringify(obj1))
obj2.a='obj2'
console.log('使用JSON对象改变obj2之后-obj1:',obj1)
console.log('使用JSON对象改变obj2之后-obj2:',obj2)
let ary1=[1,2]
let ary2=JSON.parse(JSON.stringify(ary1))
ary2.push('ary2')
console.log('使用JSON对象改变ary2之后-ary1:',ary1)
console.log('使用JSON对象改变ary2之后-ary2:',ary2)

JSON对象.jpg 3. 递归(最优解)

function deepClone(obj) {
    if (typeof obj !== 'object' || obj == null) {
        return obj
    }
    let reslut = obj instanceof Array ? [] : {}

    for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
            reslut[key] = deepClone(obj[key])
        }
    }
    return reslut
}
let obj1 = {
    age: 17,
    address: {
        "province": "广东",
        "city": "深圳"
    }
}
let obj2 = deepClone(obj1);
obj2.address.province = "陕西";
obj2.address.city = "西安";
console.log('使用深拷贝改变obj2之后-obj1:',obj1)
console.log('使用深拷贝改变obj2之后-obj2:',obj2)

deepclone.jpg