前端面试常见题|JS深浅拷贝理解及实现

106 阅读2分钟

学习这个概念花了一点时间,后来面试也被要求手写过,因此在这里记录一下自己的理解。


首先,理解这个概念的前提:深浅拷贝是针对引用类型(array、object)的讨论。而对于基本类型(number、boolean、string、null、undefined),他们的深浅拷贝并无意义,因为他们没有嵌套属性。

深拷贝的定义

MDN对深拷贝的定义:

  1. 它们不是一个对象(o1 !== o2)
  2. o1和o2的属性具有相同的名称且顺序相同
  3. 它们的属性值是彼此的深拷贝
  4. 它们的原型链深结构等价的

即:假设o2是o1的深拷贝对象,它们不能共享地址,o2需要像新开一个堆来存放数据。同时,o1和o2所有属性的值和数据类型必须一样。达成以上要求后,修改o2的任意属性都不会影响o1。

深拷贝的代码实现

假设要对以下对象进行深拷贝:

let obj1 = {
    id: 1,
    name: 'fox',
    Characteristics:{
      role: 'anti-hero',
      color: 'orange'
    }
}

使用lodash工具包里的cloneDeep函数就可以直接进行深拷贝,详细使用请见它的官方文档。 不过,为了深拷贝而特地安装一个lodash工具包太浪费资源了,更推荐使用2022年JS推出的原生深拷贝API - structuredClone(),直接使用一步到位,兼容性问题也被解决得很好:MDN上有它的详细介绍和使用方法。

但是!为了面试!最好还是要学会手写循环递归实现深拷贝!

循环递归实现

function deepClone(obj){

    //如果obj为空,不是object或array类型则不进行深拷贝
    if(obj === null || typeof obj !== "object") return obj;
    let objClone = obj instanceof Array ? [] : {};

    for(key in obj){ //开始循环拷贝obj里的每个属性
        if(obj.hasOwnProperty(key)){
            if(obj[key] && typeof obj[key] === "object"){ //判断是否是object或array类型
                objClone[key] = deepClone(obj[key]); //是则递归复制
            }
            else{
                objClone[key] = obj[key]; //不是则直接赋值
            }
        }
    }    
    return objClone;
    
}

//测试
let obj2 = deepClone(obj1);
obj2.id = 2;
obj2.Characteristics.role = 'hero';
console.log(obj2); //id被改成2,嵌套属性role被改成hero
console.log(obj1); //id仍然是1,role仍然是anti-hero


感谢观看,有问题可以在评论区友好讨论~