当前位置: 面试刷题>> 深拷贝和浅拷贝有什么区别?JS 怎么实现深拷贝?


在JavaScript中,深拷贝与浅拷贝是理解对象复制时不可回避的重要概念。它们之间的区别主要体现在复制过程中是否创建了源对象及其所有子对象的全新副本。作为高级程序员,深入理解这一区别对于编写高效、可维护的代码至关重要。

浅拷贝(Shallow Copy)

浅拷贝仅复制对象的第一层属性,如果对象的属性值是基本数据类型(如Number、String、Boolean),则直接复制其值;但如果属性值是引用数据类型(如Object、Array),则复制的是内存地址的引用,即新旧对象共享这些引用数据类型的值。这意味着,如果通过浅拷贝得到的对象修改了其内部某个引用类型属性的内容,那么原对象也会受到影响。

实现浅拷贝的方法

  1. Object.assign()

    let original = { a: 1, b: { c: 2 } };
    let copy = Object.assign({}, original);
    copy.b.c = 3; // 修改copy的b.c属性,original的b.c也会变为3
    
  2. 扩展运算符(...)

    let original = { a: 1, b: { c: 2 } };
    let copy = { ...original };
    copy.b.c = 3; // 同样,original的b.c也会受到影响
    

深拷贝(Deep Copy)

深拷贝则不同,它不仅复制对象的第一层属性,还会递归地复制所有子对象,确保新对象及其所有子对象都是完全独立的。这样,修改新对象的任何属性都不会影响到原对象。

实现深拷贝的方法

  1. JSON.parse() 和 JSON.stringify() 这是实现深拷贝的一种简单但有限制的方法,因为它无法处理函数、undefined、Symbol等特殊类型的值,也无法复制循环引用的对象。

    let original = { a: 1, b: { c: 2 } };
    let copy = JSON.parse(JSON.stringify(original));
    copy.b.c = 3; // original的b.c不会受到影响
    
  2. 手动递归实现 对于需要处理特殊类型或循环引用的场景,手动实现深拷贝是更好的选择。

    function deepClone(obj, hash = new WeakMap()) {
        if (obj === null) return null; // null 的情况
        if (obj instanceof Date) return new Date(obj); // 日期对象直接返回一个新的日期对象
        if (obj instanceof RegExp) return new RegExp(obj); // 正则对象直接返回一个新的正则对象
        // 如果循环引用了就用 weakMap 来解决
        if (hash.has(obj)) return hash.get(obj);
    
        let allDesc = Object.getOwnPropertyDescriptors(obj);
        let cloneObj = Object.create(Object.getPrototypeOf(obj), allDesc);
        hash.set(obj, cloneObj);
    
        for (let key of Reflect.ownKeys(obj)) {
            if (typeof obj[key] === 'object' && obj[key] !== null) {
                cloneObj[key] = deepClone(obj[key], hash);
            } else {
                cloneObj[key] = obj[key];
            }
        }
        return cloneObj;
    }
    
    let original = { a: 1, b: { c: 2 }, d: function() {} };
    let copy = deepClone(original);
    copy.b.c = 3; // original的b.c不会受到影响
    

总结

深拷贝与浅拷贝的核心区别在于是否创建了源对象及其所有子对象的全新副本。在JavaScript中,实现深拷贝有多种方法,每种方法都有其适用场景和限制。对于大多数基本用途,JSON.parse(JSON.stringify(obj))是一个简单快捷的选择,但在需要处理特殊类型或循环引用的复杂场景中,手动实现深拷贝则更为灵活和强大。

在深入理解这些概念的基础上,高级程序员能够根据实际需求选择最合适的复制策略,从而编写出更加健壮、高效的代码。在探索和实践的过程中,不妨关注一些高质量的编程资源,如“码小课”网站,这里汇聚了丰富的技术文章和实战案例,能够帮助你不断提升自己的编程技能。

推荐面试题