函数传参时对象被意外修改的本质是误将引用当副本,防范关键是修改前主动创建安全副本;需识别引用类型参数的副作用风险,按场景选择浅拷贝、JSON序列化、structuredClone或lodash深拷贝,并在入口处验证隔离有效性。

函数传参时对象被意外修改,本质不是“传参出了问题”,而是把引用当成了独立副本。防范关键在于:**不依赖传参自动隔离,而是在修改前主动创建安全副本**。
识别哪些传参场景必然有风险
只要函数参数是对象、数组、Date、RegExp 等引用类型,且函数内部直接修改其属性或元素,就存在副作用风险。典型例子:
-
修改对象字段:如
user.name = '新名字' -
往数组 push/splice:如
list.push(item) -
嵌套对象赋值:如
config.options.timeout = 5000
按需选择拷贝方式,别无脑深拷贝
不是所有场景都要深拷贝。选对方法既保安全又不伤性能:
-
纯配置对象(仅一层):用展开运算符
{...obj}或Object.assign({}, obj)足够安全 -
含简单嵌套(无函数、undefined、循环引用):
JSON.parse(JSON.stringify(obj))快速有效,但要提前检查数据是否可序列化 -
现代环境(Chrome 98+ / Node.js 18.16+):优先用
structuredClone(obj),支持 Map、Set、Date、RegExp 和循环引用 -
需兼容旧版或含特殊值(如函数、WeakMap):引入
lodash.cloneDeep或手写递归克隆(注意缓存已遍历对象防死循环)
在函数内部建立防御性习惯
把“是否该拷贝”变成编码本能,而不是出 Bug 后才补救:
-
入口处快速判断:函数开头加一句注释或断言,例如
// 修改 user 前已深拷贝,不影响原始数据 -
只读参数加保护:若函数本意是只读,可用
Object.freeze(obj)防止误改(开发环境启用,生产慎用) -
返回新对象而非复用入参:避免
return obj,改用return { ...obj, name: newName }或structuredClone(obj)后再改 - 对 API 响应、表单数据等外部输入,一拿到就深拷贝:防止后续任意模块修改污染源头
快速验证是否真正隔离
写完拷贝逻辑后,用两行代码验证:
const original = { a: 1, b: { c: 2 } };
const copy = /* 你的拷贝逻辑 */;
copy.b.c = 999;
console.log(original.b.c); // 应仍为 2,否则没真正隔离
这个检查比文档更可靠,建议写成单元测试用例固化下来。


















