JSON深拷贝无法处理函数和undefined是因JSON标准仅支持六种类型;structuredClone()可保留undefined并克隆函数;手写递归需用Reflect.ownKeys并分类处理;Lodash可通过customizer自定义行为。

JSON 深拷贝(JSON.parse(JSON.stringify(obj)))本身无法处理函数和 undefined,这不是 bug,而是 JSON 标准的硬性限制:它只支持字符串、数字、布尔值、null、数组和对象六种类型,其余一概不认。
为什么函数和 undefined 会丢失
函数在序列化时被完全跳过——JSON.stringify 遍历属性时,遇到 typeof value === 'function' 直接忽略,不写入字符串;undefined 在对象中作为属性值时也被静默剔除(如 { a: undefined } → {}),在数组中则变成 null(如 [1, undefined, 3] → [1, null, 3])。
现代浏览器首选 structuredClone()
Chrome 98+、Firefox 94+、Node.js 18.13+/20.6+ 已原生支持 structuredClone(),它能正确保留 undefined 字段,并对函数做引用克隆(函数体不变,但 this 和闭包需自行验证):
使用约定式提交(Conventional Commits)生成标准化的 Git 提交信息。适用于以下场景: (1) 暂存更改时需要提交信息; (2) 审查 diff 时希望获得结构化摘要; (3) 编写 PR 描述或变更日志(changelog)条目; (4) 用户明确要求“为本次更改编写提交信息”。 该功能会分析已暂存/未暂存的 diff,并生成按类型(type)划分范围的提交信息。
-
structuredClone({ a: undefined, b() {} })→ 返回对象含a: undefined,b是原函数引用 - 支持
Date、RegExp、Map、Set、循环引用,且无需额外判断 - 不支持
Symbol、Promise、DOM 节点,但已覆盖函数与undefined的核心需求
兼容旧环境或需精细控制时手写递归
用 WeakMap 防循环引用,用 Reflect.ownKeys() 拿全键(含不可枚举和 Symbol),再分类处理:
立即学习“Java免费学习笔记(深入)”;
- 遇到
undefined:直接赋值cloned[key] = obj[key] - 遇到函数:可原样赋值(保留引用),或用
value.bind({})创建无依赖副本 - 遇到
RegExp:用new RegExp(value.source, value.flags)新建实例 - 遍历用
Reflect.ownKeys(obj),而非for...in或Object.keys(),避免漏掉 Symbol 键
用 Lodash 并自定义 customizer
_.cloneDeep() 默认丢弃函数和 undefined,但可通过 customizer 回调干预:
- 对函数显式返回自身:
if (typeof value === 'function') return value - 对
undefined,建议前置标准化:用JSON.stringify(obj, (k, v) => v === undefined ? null : v)把undefined转为null,再解析 + 深拷贝 - 对
RegExp,在 customizer 中检测value instanceof RegExp后返回新实例

















