闭包本身不加重内存压力,问题在于无意中捕获不该长期持有的数据;应只传必要参数、避免挂载长生命周期宿主、配对清理事件与定时器、优先用类封装可销毁状态。

函数式编程本身不加重内存压力,问题出在闭包无意中捕获了不该长期持有的数据。关键不是减少闭包使用,而是让每次闭包只“拿”它真正需要的那一点,用完即断。
只传必要参数,不捕获整个对象
闭包会把所有被访问的外层变量打包封存。哪怕你只用 user.name,整个 user 对象(含头像、权限树、日志数组)都会被锁住。
- ❌ 避免:
const handler = () => apiCall(user)—— 直接传入大对象 - ✅ 改为:
const handler = () => apiCall(user.id, user.role)或提前解构:const { id, role } = user; const handler = () => apiCall(id, role) - 对配置类或上下文,转成 plain object、Map 或结构化对象,剥离方法和内部状态
避免闭包挂到长生命周期宿主上
一旦闭包赋值给 window、模块顶层变量或全局缓存,它捕获的作用域就等于被钉死在整个页面生命周期里。
- 启用 "use strict",配合 ESLint 的 no-implicit-globals 规则,防止漏写 const/let 导致隐式挂载
- 模块导出函数时,别在初始化阶段捕获大数据:
const data = fetchBigList(); export const fn = () => data.map()→ 改为export const fn = (data) => data.map()或用工厂函数按需生成 - 真需缓存(如主题处理器),用 WeakMap 关联 DOM 元素与闭包,元素销毁后缓存自动失效
事件与定时器必须配对清理
函数式风格常把处理逻辑封装成纯函数或高阶函数,但一旦作为回调挂到事件或定时器上,它就不再是“纯”的了——它有了生命周期。
- 事件监听不用箭头函数或匿名函数,改用具名函数或保存引用,确保能精准调用 removeEventListener
- 定时器返回的 ID 必须保存,并在组件卸载、任务结束或页面隐藏前调用 clearInterval / clearTimeout
- React 中利用 useEffect 清理函数,Vue 用 onBeforeUnmount,原生 JS 可维护 cleanup 数组统一销毁
- 卸载前,将闭包内强引用的 DOM 节点、大数据对象显式设为 null
优先用类或可销毁对象管理有状态逻辑
函数式强调无状态,但现实业务总有状态要管。与其让闭包偷偷藏状态,不如明确定义边界。
- 把需要管理资源(如 WebSocket、Canvas、定时器)的逻辑封装成类,提供 .close() 或 .destroy() 方法
- 类实例可主动控制生命周期,比依赖作用域自动退出更可靠、更易测试
- 配合框架清理钩子或手动调用,形成“创建–使用–销毁”闭环,避免闭包暗中拖住一堆对象
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











