JSON.stringify配合JSON.parse可实现纯数据对象的深拷贝,但会丢失函数、undefined、Symbol、Date、RegExp等不可序列化类型,适用于无行为、可序列化的DTO或表单数据。
函数不能作为对象的键名——这是 JavaScript 的基本规则。当你写
,实际执行时,函数会先被隐式转换为字符串
(或空字符串),最终键名变成字符串,而非函数本身。因此,“函数作为键名”在 JS 中根本不会存在,也就谈不上“在深拷贝中丢失”。真正需要警惕的,是
函数作为属性值
时,在深拷贝中被静默丢弃所引发的引用丢失与逻辑断裂。
为什么函数作为属性值会被深拷贝丢弃
JSON 序列化标准不支持函数类型。只要用
,所有函数属性都会被跳过:
→
后续
得到的对象里,
属性彻底消失
调用
会报
哪些深拷贝方式会触发这种断裂
以下方法在处理含函数的对象时,均会导致行为逻辑不可用:
:最常见,也最危险——函数、
、
全部消失
:现代原生方案,但明确不支持函数和
,遇到即静默剔除
简易手写递归(未做类型分支):若没判断
,可能把函数当普通对象递归,结果报错或返回空对象
如何提前识别这类风险
不是等报错才发觉,而是主动探测:
检查原始对象是否有
的属性
对关键对象运行
,看是否出现
占位符——说明它本该存在,但标准序列化会抹掉
使用
列出所有函数属性,评估是否可被舍弃
修复逻辑断裂的实用策略
函数不能“拷贝”,但可以“重建”或“绕过”:
分离数据与行为
:把函数抽成独立工具函数,对象只存配置项(如
),运行时按 type 分发调用
白名单重建
:深拷贝后,手动补回必要函数:
(适用于已知固定接口)
改用结构化克隆 + 补丁
:先
,再遍历原始对象,对每个函数属性做赋值覆盖(注意避免污染原型)
换库兜底
:如需完整保留,用
—— 它虽不拷贝函数体,但至少保留函数引用(非字符串化),适合跨 iframe 或需保持闭包上下文的场景
{ [someFunc]: 'value' }"function () { ... }"JSON.stringify{ name: 'Alice', action: () => console.log('run') }{"name":"Alice"}JSON.parseactioncopy.action()TypeError: copy.action is not a functionJSON.parse(JSON.stringify(obj))undefinedSymbolstructuredClone(obj)undefinedtypeof value === 'function'typeof obj[key] === 'function'JSON.stringify(obj, (k, v) => typeof v === 'function' ? '[Function]' : v)[Function]Object.getOwnPropertyNames(obj).filter(k => typeof obj[k] === 'function'){ type: 'save', payload: {...} }copy.handler = original.handlerstructuredClonelodash.cloneDeep