闭包用于隔离和持久化深拷贝中的状态,核心是通过内部 weakmap 缓存已拷贝对象以解决循环引用;每次调用 deepclone 创建独立闭包,保证 cache 私有、互不干扰且自动清理。

闭包在手写深拷贝中主要用于**隔离和持久化递归过程中的状态**,特别是解决循环引用问题——核心是用一个外部作用域的 Map(或 WeakMap)缓存已拷贝过的对象及其对应的新对象,后续遇到重复引用时直接返回缓存结果,从而打断无限递归。
用闭包维护「已拷贝对象映射表」
循环引用的本质是:A 引用了 B,B 又引用了 A。若不记录历史,递归拷贝会陷入死循环。闭包可将 `cache`(如 Map)封闭在函数内部,避免污染全局,同时让每次递归调用都能访问同一份状态。
示例结构:
function deepClone(obj) {
const cache = new WeakMap(); // 用 WeakMap 更安全,避免内存泄漏
function clone(target) {
if (target === null || typeof target !== 'object') return target;
// 检查是否已拷贝过
if (cache.has(target)) return cache.get(target);
// 创建新对象(数组 or 普通对象)
const cloned = Array.isArray(target) ? [] : {};
// 立即缓存,防止自身循环(如 obj.a = obj)
cache.set(target, cloned);
// 递归拷贝属性
for (const key in target) {
if (Object.prototype.hasOwnProperty.call(target, key)) {
cloned[key] = clone(target[key]);
}
}
return cloned;
}
return clone(obj);
}
为什么必须用闭包?不能把 cache 放参数里吗?
可以,但不简洁。若把 cache 作为参数传入递归函数,每次调用都要显式传递,易出错且破坏接口纯净性。闭包让 clone 函数天然“记住”当前拷贝任务的上下文,使用者只需调用 deepClone(obj),内部状态自动管理。
- 闭包使状态私有:外部无法误改或清空 cache
- 支持多次独立调用:每次
deepClone()调用都创建新闭包,互不影响 - WeakMap + 闭包 = 安全生命周期:当原始对象被回收,cache 中对应条目也会被自动清理
处理特殊对象(Date、RegExp、Map、Set)时仍需闭包状态
扩展深拷贝时,遇到内置类型需单独处理。这些逻辑仍共享同一个 cache,否则 Map/Set 的嵌套循环引用仍会失效。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
例如拷贝 Map:
if (target instanceof Map) {
const clonedMap = new Map();
cache.set(target, clonedMap); // 同样先缓存,再遍历
target.forEach((value, key) => {
clonedMap.set(clone(key), clone(value));
});
return clonedMap;
}
这里 clone(key) 和 clone(value) 仍走同一个闭包内的 clone 函数,复用同一 cache,确保 key 或 value 若指向父对象,也能命中缓存。
不推荐用普通对象或全局变量模拟闭包
有人试图用全局 const globalCache = new WeakMap(),但这会导致多个深拷贝调用互相干扰;也有人用参数透传 cache,导致调用签名变丑(clone(obj, cache))。闭包是更自然、更健壮的封装方式。
关键点不是“用了闭包”,而是**用闭包把一次拷贝任务所需的全部中间状态(cache + 递归函数)绑定在一起**,形成一个自包含、可重入、线程安全(单线程 JS 下)的拷贝单元。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










