60 秒回答模板

闭包是函数和其词法环境的组合。内部函数在定义时会记住可访问的外层作用域,即使外层函数已经执行结束,只要内部函数还被引用,相关外层变量就不会被释放。闭包常用于封装私有状态、函数工厂、缓存、防抖节流、事件回调和模块化。它的风险是长期持有大对象、DOM 节点或过期上下文,导致内存无法回收;所以闭包不是天然内存泄漏,关键看引用是否仍然必要。

考点 核心机制与工程取舍
难度 中高频面试题
回答目标 按定义、机制、场景讲清楚

深入解析

01

词法作用域基础

JS 函数能访问自己定义位置外层作用域中的变量,这由词法作用域决定。闭包不是特殊语法,而是函数引用外层变量后形成的运行时现象。

02

为什么变量还在

外层函数返回后,正常情况下执行上下文会结束。但如果返回的内部函数仍引用外层变量,引擎必须保留这些变量,直到内部函数也不再可达。

03

典型用途

闭包可以隐藏私有变量,生成带配置的函数,保存防抖节流的定时器,给事件回调保存上下文,或在模块作用域中维护缓存。

04

循环和异步场景

闭包保存的是变量绑定,不是每次循环值的快照。let 会为每轮循环创建新的绑定;var 在循环中共享同一绑定,所以异步回调里常出现同一个最终值。

05

内存风险

如果闭包被全局缓存、事件监听器或长期定时器持有,它引用的大对象和 DOM 节点也会被保留。用完后应移除监听、清理定时器、释放无用引用。

06

回答边界

闭包本身是语言能力,不是坏事。面试要把优点和风险分开讲:它提供状态封装,但需要管理生命周期。

易错点

  • 不要把闭包说成“函数内部再写函数”就完了,关键是内部函数引用外层词法环境。
  • 不要说闭包一定内存泄漏。泄漏取决于无用引用是否长期可达。
  • 不要忽略 var 循环共享绑定的问题,这是闭包高频追问。
  • 不要只讲概念不讲用途。私有状态、防抖节流和函数工厂都是常见落点。

面试官追问

闭包一定会造成内存泄漏吗?

不会。闭包只是保留仍被引用的变量。只有这些引用已经不需要却长期可达,才会变成泄漏。

var 循环里闭包为什么常拿到同一个值?

var 是函数作用域,循环共享同一个 i 绑定。异步回调执行时循环已结束,所以读到最终值。let 会为每次迭代创建新绑定。

闭包和模块化有什么关系?

模块或函数可以用闭包隐藏内部状态,只暴露有限方法。外部不能直接访问私有变量,只能通过返回的函数操作。

怎么降低闭包带来的内存风险?

及时移除事件监听和定时器,避免缓存无上限增长,不在闭包中持有不必要的大对象或 DOM 引用。