JavaScript深拷贝无法真正复制函数,因其是不可序列化的引用类型;JSON会直接丢弃函数,手写递归通常原样保留、跳过或慎用包装,structuredClone也不支持函数,本质是函数属逻辑而非数据。

JavaScript 中深拷贝无法真正“复制”函数,因为函数是不可序列化的引用类型——它没有结构化的值可递归遍历,也没有内存地址可安全克隆。所谓“处理多层嵌套的函数”,实际是指:在深拷贝过程中,如何合理保留、跳过或重建这些函数,而不是字面意义地复制函数体和闭包。
为什么 JSON 方法对函数完全失效
像 JSON.parse(JSON.stringify(obj)) 这类方案会直接丢弃函数(以及 undefined、Symbol、Date、RegExp 等),因为 JSON 标准不支持它们。函数字段在序列化后消失,反序列化后该属性就不存在了。
- 原对象有
fn() { console.log(this.name) }→ 字符串化后变成空字段 - 还原后对象中
fn属性为undefined,调用会报错
手写递归深拷贝时对函数的常见策略
手动实现深拷贝(如用 WeakMap 解决循环引用)时,函数通常不被递归处理,而是按需选择以下一种方式:
-
原样保留(推荐默认做法):检测到
typeof obj === 'function',直接赋值原函数,不递归也不修改。这最符合语义——函数本就是可复用的行为定义,无需“复制” - 忽略/跳过:不把函数写入新对象,相当于删除该属性(类似 JSON 行为)
-
包装为新函数(慎用):例如
() => originalFn.call(...arguments),但会丢失this绑定、name、length、闭包变量等,实用性低
生产环境建议:明确需求,避免强行“拷贝函数”
绝大多数场景下,你并不需要拷贝函数本身:
立即学习“Java免费学习笔记(深入)”;
- 如果函数只作配置或回调使用,保留引用完全安全
- 如果函数依赖内部闭包状态(比如私有变量),复制毫无意义——新函数无法访问原闭包
- 若真需隔离行为(如插件系统),应通过工厂函数或 class 实例化,而非拷贝已有函数
现代替代方案:structuredClone() 的限制与现实
浏览器原生的 structuredClone()(2022 年起支持)仍不支持函数、undefined、Symbol,遇到函数会直接抛错:DataCloneError。所以即使使用它,也必须提前过滤或预处理含函数的对象。
例如:
const cleanForClone = (obj) => {
const copy = Array.isArray(obj) ? [] : {};
for (const [k, v] of Object.entries(obj)) {
if (typeof v !== 'function') copy[k] = v;
}
return copy;
};
const safeCopy = structuredClone(cleanForClone(original));
不复杂但容易忽略:深拷贝的本质是数据隔离,而函数不是数据——它是逻辑。处理嵌套函数的关键,是承认它不该被拷贝,而是被设计成可复用、无副作用、不依赖私有状态的形式。


















