Blog Detail

  • 如何避免修改对象内部数组的对象字段时篡改原对象?

    解决对象深拷贝问题:修改嵌套属性不影响原对象

    你遇到的核心问题是浅拷贝的局限性:Object.assign()和扩展运算符(...)仅复制对象的顶层属性,对于嵌套的数组、对象这类引用类型,它们复制的是内存地址而非实际内容。这就导致修改拷贝后的嵌套属性时,原对象会同步被修改。

    以下是几种可行的深拷贝解决方案:

    1. 手动实现深拷贝

    通过递归遍历对象的每一层属性,对引用类型进行逐层复制:

    function deepClone(obj) {

    // 非对象类型直接返回

    if (obj === null || typeof obj !== 'object') return obj;

    // 处理数组

    if (Array.isArray(obj)) {

    return obj.map(item => deepClone(item));

    }

    // 处理普通对象

    const cloned = {};

    for (const key in obj) {

    if (obj.hasOwnProperty(key)) {

    cloned[key] = deepClone(obj[key]);

    }

    }

    return cloned;

    }

    // 测试使用

    const originalObject = {

    name: "John Doe",

    age: 30,

    arr: [{ num: 1 }]

    };

    const copied = deepClone(originalObject);

    copied.arr[0].num = 2;

    console.log(originalObject.arr[0].num); // 输出1,原对象未被修改

    2. 使用JSON序列化/反序列化

    这是最简便的方式,但存在局限性:无法拷贝函数、Symbol、循环引用,以及Date、RegExp这类特殊对象会被转成字符串或普通对象:

    const copied = JSON.parse(JSON.stringify(originalObject));

    copied.arr[0].num = 2;

    console.log(originalObject.arr[0].num); // 输出1

    3. 原生结构化克隆(Structured Clone)

    现代浏览器和Node.js(v17+)原生支持的API,能处理更多类型(Date、RegExp、Map、Set等),但仍不支持函数:

    // 浏览器环境

    const copied = structuredClone(originalObject);

    // Node.js环境

    const { structuredClone } = require('node:util');

    const copied = structuredClone(originalObject);

    copied.arr[0].num = 2;

    console.log(originalObject.arr[0].num); // 输出1

    4. 使用第三方库(如Lodash)

    如果项目已引入Lodash,直接使用成熟的深拷贝方法:

    const _ = require('lodash');

    const copied = _.cloneDeep(originalObject);

    copied.arr[0].num = 2;

    console.log(originalObject.arr[0].num); // 输出1

    方法选择建议

    若需自定义拷贝逻辑或无依赖场景:手动实现深拷贝

    简单场景且无特殊类型:JSON序列化方案

    现代环境且需支持更多类型:结构化克隆API

    复杂项目或已有Lodash依赖:使用_.cloneDeep

    内容的提问来源于stack exchange,提问作者ThavinV