深拷贝与浅拷贝

71 阅读2分钟

参考博文:浅拷贝与深拷贝浅拷贝是创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的 - 掘金 (juejin.cn)

基本数据类型

1.栈存放;2.值不可变;3.值比较;4.赋值传值

引用数据类型

1.堆存放,栈存地址;2.值可变;3.地址比较;4.赋值传址

赋值和浅拷贝的区别

对于引用对象而言,赋值是地址指向同一内存,改变的是同一个对象,因此改变基本数据和子对象都会相互影响。浅拷贝则是开辟一个新的内存空间,改变的不是同一个对象,基本数据拷贝到新对象中改变不会相互影响,而子对象是拷贝的地址,所以子对象的改变会相互影响。

1724242999261.png

浅拷贝和深拷贝的区别

浅拷贝和深拷贝是基于引用数据对象而言的,浅拷贝会拷贝子对象的地址到新对象中,导致原始对象和新拷贝的对象修改子对象数据时会相互影响,而深拷贝则是完整拷贝子对象的数据,使得新旧数据数据完全分离,修改时不会相互影响。

image.png

浅拷贝方法

  • Object.assign()
  • ...展开运算符
  • Array.prototype.contact()
  • Array.prototype.slice()
  • lodash库的_clone方法

深拷贝方法

  • JSON.Parse(JSON.Stringify()) -----缺点是正则和函数无法正确拷贝,也会存在循环引用等问题
  • 递归手写deepClone方法

1.weakMap处理循环引用

2.处理特殊对象Set、Map、Date、RegExp

3.处理数组对象

// 深拷贝
const _deepClone = (target, map=new WeakMap()) => {
    // 如果是基础类型直接返回
    if(typeof target !== 'object' || target == null) return target
    // 如果map中已存在拷贝的对象则直接返回拷贝对象
    if(map.get(target)) return map.get(target)
    // 新建一个空的拷贝对象
    let cloneTarget = new target.constructor()
    // 将拷贝对象存入map中
    map.set(target, cloneTarget)

    // 日期类型
    if (target instanceof Date) return new Date(target);
    // 正则类型
    if (target instanceof RegExp) return new RegExp(target);

    // set类型数据
    if(target instanceof Set){
        target.forEach((v) => {
            cloneTarget.add(_deepClone(v, map))
        })
    }

    // map类型数据
    if(target instanceof Map){
        target.forEach((v, k) => {
            cloneTarget.set(_deepClone(k, map), _deepClone(v, map))
        })
    }

    // Array or Object
    for(let key in target){
        if(target.hasOwnProperty(key)){
            cloneTarget[key] = _deepClone(target[key], map)
        }
    }

    return cloneTarget
}