“手写深浅拷贝”到底怎么考?用真实代码带你拆穿JS对象复制的所有套路!

114 阅读2分钟

一、为什么要拷贝对象?

想象一下,你有一份重要的文件(对象),你想给朋友一份副本。
如果只是把文件夹路径发给他(浅拷贝),你俩其实用的是同一份文件,谁改了内容都会影响对方。
如果你给他一份真正的复印件(深拷贝),你们互不影响,各玩各的。


二、JS里的数据存储和类型

  • 基本类型(number、string、boolean、null、undefined、symbol、bigint):直接存储在栈内存,赋值就是复制一份,互不影响。
  • 引用类型(对象、数组、函数等):存储在堆内存,变量里存的是“地址”,赋值只是复制地址,指向同一个对象。

三、浅拷贝:只复制一层,容易“牵一发动全身”

1. 常见浅拷贝方法

  • Object.assign({}, obj)
  • ...扩展运算符([...arr]{...obj}
  • Array.prototype.slice()
  • Array.prototype.concat()
  • Object.create(obj)
  • arr.toReversed().reverse()

2. 手写一个浅拷贝

function shallowCopy(obj) {
    let newObj = {};
    for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
            newObj[key] = obj[key];
        }
    }
    return newObj;
}

3. 浅拷贝的坑

let obj = {
    name: 'Ricardo',
    like: { a: '唱', b: '跳' }
};
let newObj = shallowCopy(obj);
obj.like.a = '篮球';
console.log(newObj.like.a); // '篮球',浅拷贝只复制了第一层,内部对象还是同一个!

四、深拷贝:层层复制,互不影响

1. 常见深拷贝方法

  • JSON.parse(JSON.stringify(obj))
    缺点:丢失undefinedfunctionsymbol,不能处理循环引用,bigint也不行。
  • structuredClone(obj)
    优点:支持循环引用、undefinedbigint,但functionsymbol还是丢失。

2. 手写一个简单深拷贝

function deepCopy(obj) {
    let newObj = {};
    for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
            if (typeof obj[key] === 'object' && obj[key] !== null) {
                newObj[key] = deepCopy(obj[key]);
            } else {
                newObj[key] = obj[key];
            }
        }
    }
    return newObj;
}

3. 深拷贝的效果

let obj = {
    name: 'Ricardo',
    like: { a: '唱', b: '跳' }
};
let newObj = deepCopy(obj);
obj.like.a = '篮球';
console.log(newObj.like.a); // 还是'唱',深拷贝互不影响!

五、各种拷贝方法的优缺点对比

方法是否深拷贝支持循环引用支持function/symbol支持bigint速度
Object.assign/扩展运算符-
JSON.parse(JSON.stringify)较快
structuredClone
手写递归取决于实现取决于实现

六、面试高频陷阱

  1. 浅拷贝后改内部对象,两个对象都变?
  2. JSON深拷贝丢失特殊类型?
  3. 循环引用导致JSON方法报错?
  4. 如何优雅处理大对象的深拷贝?

七、实际开发建议

  • 只需要复制一层,用浅拷贝,速度快。
  • 需要彻底隔离,用深拷贝,优先structuredClone
  • 兼容性要求高时,手写递归。
  • 注意特殊类型和循环引用,别一味用JSON方法。

八、总结

拷贝对象看似简单,实则暗藏玄机。浅拷贝适合简单场景,深拷贝才是真正的“断舍离”。理解原理、掌握方法,才能在开发和面试中游刃有余。下次再遇到“拷贝”相关问题,你一定能自信应对!