深入理解深拷贝和浅拷贝

62 阅读2分钟

深拷贝和浅拷贝

1、工作中频率最高的深浅拷贝

//object.assign
Object.assign({}, obj):obj为单层对象能实现"深拷贝";obj为深层对象,则只能视为浅拷贝
//JSON.parse(JSON.stringify(xxx))
只能实现普通对象(function,Symbol(),undefined这三种除外)的深拷贝,当对function,Symbol(),undefined这三种进行拷贝时,会造成数据丢失

2、object.assign()

let obj = {a:1,b:2}
let newObj = {...obj}
newObj.a = 5
console.log(obj.a) //1
let obj1 = {a:{c:5},b:2}
let newObj1 = {...obj1}
newObj1.a.c = 10
console.log(obj1.a.c) //10

3、JSON.parse(JSON.stringify(xxx))

let test = {
      a:{
        c:5
      },
      arr:[1,2],
      fuc:function(){
        console.log("fuc");
      },
      u:undefined,
      b:8,
      s:Symbol(),
      n:null,
      t:true
    }
    let copy = JSON.parse(JSON.stringify(test))
    console.log("copy", copy);
    test.a.c = 7
    console.log(copy.a.c); //5
    test.t = false
    console.log(copy.t);//true
    test.b = 10
    console.log(copy.b); //8

image-20231101095149100转存失败,建议直接上传图片文件

JSON.parse(JSON.stringify(XXX))能实现大部分数据类型的深拷贝,但是当拷贝数据类型为Symbol、undefined和function时,则会造成数据的丢失。

  • 注意:当数据类型为BigInt时,会报错显示JSON.stringify无法序列化BigInt。
  • 如果想进一步理解,需要去对JSON.parse()和JSON.stringify()更深一步的了解

4、简单的深拷贝

//只针对对象和数组
function deepClone(obj) {
    let cloneObj = obj instanceof Array ? [] : {}
    for(let item in obj) {
        cloneObj[item] = typeof obj[item] === "object" ? deepClone(obj[item]) : 		obj[item]
    }
    return cloneObj
}

5、数据类型的检测

  • typeof一般用于检测基本数据类型,检测引用数据类型都返回Object

    • //注意:typeof检测null也会返回object,用typeof检测function返回的function
  • instanceof主要是用来检测引用数据类型,不能用来检测基本数据类型。A instanceof B,如果A是B的实例对象,则返回true,否则返回false。即如果能在A的原型链上找到B的原型,则为true

    • //注意:[] instanceof Object 也为true,这是因为[].proto ->Array.prototype,Array.prototype._proto_指向Object.prototype。类似的,Date、RegExp和函数也会形成这样的一条原型链。
  • constructor根据数据类型的构造函数返回类型,null和undefined没有构造函数,因此不能判断

  • Object.prototype.toString.call()可以准确的检测所有数据类型

6、复杂的深拷贝

//考虑RegExp、Date
function deepClone(target, map = new Map()) {
    if(target instanceof RegExp) return new RegExp(target)
    if(target instanceof Date) return new Date(target)
    if(typeof target === "object" && targrt !== "null" && target !== "undefined") {
        let cache = map.get(target)
        if(cache) return
        let result = new target.constructor
        map.set(target,result)
        if(Array.isArray(target)){
            target.forEach((item, key) => {
                result[key] = deepClone(item, map)
            })
        }else {
            Object.keys(target).forEach(key => {
                result[key] = deepClone(target[key], map)
            })
        }
        return result
    }else {
        return target
    }
}

参考文章:juejin.cn/post/707004… juejin.cn/post/700767…