函数对象在JavaScript深拷贝中默认保留引用而非递归复制,因其内部代码、闭包、this绑定等无法通过JS API访问或重建;常见策略包括忽略函数、删除函数字段、替换为占位函数或手动重绑定(但有局限性)。

JavaScript 中手写深拷贝时,函数对象默认不被递归复制,而是直接保留引用。这是因为函数是不可变的(其代码逻辑无法被“深拷贝”),且多数场景下共享函数体是合理且高效的。但若你明确需要“重新绑定”或“隔离函数上下文”,需额外处理——这不是传统深拷贝的职责,而是业务逻辑层面的定制需求。
为什么函数通常不深拷贝
函数在 JS 中是第一类对象,但其内部代码([[Code]]、[[Environment]] 等)无法通过 JavaScript 暴露的 API 访问或重建。new Function(source) 仅能重建函数逻辑,无法还原闭包、this 绑定、原型链或私有词法环境。因此,标准深拷贝(如 structuredClone、JSON 序列化、Lodash.cloneDeep)均跳过函数,原样保留引用。
常见处理策略(按需选择)
注意:以下操作都属于“定制行为”,不是通用深拷贝的一部分。
- 忽略函数(推荐默认做法):遍历对象时检测到 function 类型,直接赋值原引用。适用于绝大多数场景,保证性能与语义正确性。
- 删除函数字段:在拷贝前过滤掉所有函数属性(例如用 Object.keys().filter(k => typeof obj[k] !== 'function'))。适合序列化或跨环境传输(如发给后端)。
- 替换为占位函数或空函数:例如 value => typeof value === 'function' ? () => {} : deepClone(value)。可用于测试桩或沙箱隔离。
- 手动重绑定 this(仅限 bind/箭头函数等可识别情况):对已绑定函数(如 fn.bind(ctx)),可尝试提取原始函数和绑定参数,再用新上下文重新 bind;但无法还原箭头函数的词法 this,也无法恢复 class 方法的内部绑定机制。
一个轻量示例(支持忽略函数)
以下是一个简化版手写深拷贝,显式跳过函数:
立即学习“Java免费学习笔记(深入)”;
function deepClone(obj) {
if (obj === null || typeof obj !== 'object') return obj;
if (typeof obj === 'function') return obj; // 直接返回引用
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
const cloned = Array.isArray(obj) ? [] : {};
for (const key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
cloned[key] = deepClone(obj[key]);
}
}
return cloned;
}
关于“重新绑定”的现实约束
所谓“重新绑定函数”,本质是创建新函数并指定 this 和参数。但原始函数若依赖闭包变量、私有状态(如模块内 let 变量)、或 class 私有字段(#field),这些无法被任何运行时方法重建。强行模拟只会丢失行为一致性。因此,真正需要隔离上下文的场景,应从设计入手:避免将可变状态封闭在函数闭包中;改用可序列化的配置对象 + 纯函数组合。


















