面试又被问到深拷贝浅拷贝的区别了,该怎么回答呢?

4 阅读2分钟

JaveScript数据类型存储

  • 简单类型:栈存储;
  • 引用类型:堆存储,引用类型的变量是一个指向堆内存中的一个指针,将指针保存在栈内存中;

浅拷贝

定义

浅拷贝创建一个新对象,仅复制对象的第一层属性

如果属性是基本类型,拷贝的就是基本类型的值。如果属性是引用类型,拷贝的就是内存地址

实现方式

  1. 扩展运算符(...)
const obj = { a: 1, b: { c: 2 } };
const shallowCopy = { ...obj };

2.Object.assign():

const shallowCopy = Object.assign({}, obj);

注意

修改改原对象的引用类型属性会影响到拷贝后的对象:


obj.b.c = 99;
console.log(shallowCopy.b.c); // 输出 99

深拷贝

深拷贝创建一个新对象,并递归复制所有层级的属性,新旧对象完全独立,不共享任何引用。

实现方法:

  1. JSON.parse(JSON.stringify(obj))

    const obj = { a: 1, b: { c: 2 } };
    const deepCopy = JSON.parse(JSON.stringify(obj));
    

    缺点

    • 无法处理函数Symbolundefined
    • 会丢失Date对象(转为字符串)。
    • 无法处理循环引用(如 obj.self = obj 会报错)。
  2. 递归实现
    手动实现深拷贝,处理多种数据类型:

    function deepClone(source, map = new WeakMap()) {
        // 简单类型直接返回
        if (source === null || typeof source !== 'object') return source;
        if (map.has(source)) return map.get(source); // 解决循环引用
        
        const target = Array.isArray(source) ? [] : {};
        map.set(source, target);
        
        for (const key in source) {
            if (source.hasOwnProperty(key)) {
                target[key] = deepClone(source[key], map);
            }
        }
        return target;
    }
    
  3. 第三方库

    • Lodash的_.cloneDeep()

      const _ = require('lodash');
      const deepCopy = _.cloneDeep(obj);
      

特点

  • 完全独立的对象,修改原对象的任何属性不会影响拷贝后的对象:

    obj.b.c = 99;
    console.log(deepCopy.b.c); // 输出 2
    

总结:讲一讲深拷贝和浅拷贝的区别

如果拷贝的类型为引用类型,浅拷贝只会复制一层,如果属性值依旧是一个引用类型,则会共享同一个引用地址,表现为修改改原对象的引用类型属性会影响到拷贝后的对象。深拷贝会递归复制所有层级的属性,完全断开引用关系,生成一个完全独立的新对象,修改任何一方都不会影响另一方。