JavaScript中避免修改原对象,传递对象的最佳方式及替代方案
关于JavaScript中避免修改原对象的方案解析
你已经明确JavaScript中对象是按引用传递,在函数内修改会影响原对象,并且用扩展运算符{...obj}创建副本的方式是可行的,但它属于浅拷贝,是否是“最佳方案”得看你的具体场景,下面给你几种常见的替代方案和适用场景:
一、浅拷贝方案(适合单层结构对象)
如果你的对象只有一层属性(没有嵌套的对象/数组),这些方法足够用:
- 扩展运算符:就是你用的
const newObj = {...obj},写法简洁直观,是日常开发中最常用的方式之一。 - Object.assign():和扩展运算符效果完全一致,
const newObj = Object.assign({}, obj),同样只复制对象的第一层属性。
注意:浅拷贝的局限性在于,若对象里嵌套了其他对象或数组,拷贝后嵌套部分依然是引用关系,修改嵌套内容还是会影响原对象。
二、深拷贝方案(适合多层嵌套结构)
如果对象有多层嵌套,需要彻底切断和原对象的引用关系,就得用深拷贝:
- JSON序列化/反序列化:
const newObj = JSON.parse(JSON.stringify(obj)),写法最简单,但有明显局限——无法处理函数、Symbol、循环引用、undefined这些类型,会直接丢失这些内容,适合结构简单且无特殊类型的对象。 - 手写递归深拷贝:可以自定义处理各种数据类型,适合有特殊需求的场景,示例代码:
function deepClone(obj) { // 非对象类型直接返回 if (obj === null || typeof obj !== 'object') return obj; // 处理Date类型 if (obj instanceof Date) return new Date(obj); // 处理数组类型 if (obj instanceof Array) return obj.map(item => deepClone(item)); // 处理普通对象 const newObj = {}; for (let key in obj) { if (obj.hasOwnProperty(key)) { newObj[key] = deepClone(obj[key]); } } return newObj; } - 第三方库(如Lodash的_.cloneDeep()):如果项目中已经引入了Lodash这类工具库,直接用
_.cloneDeep(obj)最省心,它能处理各种边界情况,成熟稳定。
三、不可变数据工具(适合频繁修改不可变数据的场景)
如果你的业务需要频繁处理不可变数据(比如React状态管理),可以用Immer库,它允许你以“直接修改”的写法操作副本,底层自动生成新的不可变对象,代码更简洁:
import { produce } from 'immer'; function test(obj) { const newObj = produce(obj, draft => { draft.a = 7; // 这里看似修改原对象,实际是操作Immer生成的草稿对象,最终返回新对象 }); }
总结
- 单层对象:扩展运算符或
Object.assign()是轻量高效的最佳选择; - 多层嵌套对象:根据是否有特殊类型,选择JSON方法(简单场景)、手写深拷贝(自定义需求)或第三方库(稳定可靠);
- 频繁处理不可变数据:Immer能大幅提升开发体验。
内容的提问来源于stack exchange,提问作者Programmer
相关产品推荐
相关产品推荐

