JavaScript闭包是函数与其定义时词法作用域的组合,需满足嵌套函数、引用外部变量、外部函数返回内部函数三个条件,用于实现私有变量封装、事件状态保持、柯里化、防抖节流等。
JavaScript 闭包是指一个函数能够记住并访问其词法作用域,即使这个函数在其原始作用域之外执行。简单说,闭包 = 函数 + 该函数定义时所处的作用域环境。
当内部函数引用了外部函数的变量,并且这个内部函数在外部函数返回后仍被调用,JavaScript 引擎就会保留外部函数的作用域链,不让其中的变量被垃圾回收——这就形成了闭包。
关键点:
闭包是实现“私有成员”的主要手段,避免全局污染,同时提供可控的访问接口。
例如创建一个计数器模块:
const createCounter = () => {这里的 count 不会被外部直接修改,只能通过暴露的方法操作,这就是闭包带来的数据封装能力。
在循环绑定事件时,常见需求是让每个回调“记住”它对应的数据项。不使用闭包容易出现所有回调共享同一个变量值的问题。
典型写法(ES5 常见):
for (var i = 0; i (function(index) {现代写法则更简洁(用 let 声明块级作用域变量,本质也是利用了作用域+闭包逻辑):
for (let i = 0; i setTimeout(()
=> console.log(i), 100);闭包适合预先填充部分参数,生成定制化函数。比如日志工具按环境输出不同前缀:
const createLogger = (prefix) => (message) => console.log(`[${prefix}] ${message}`);这种模式在中间件、工具函数、API 封装中很常见,提升复用性和可读性。
用户频繁触发事件(如 resize、input)时,需要控制执行频率。这类函数依赖闭包保存定时器 ID 和上一次触发时间等状态。
简易防抖示例:
const debounce = (fn, delay) => {这里的 timer 被闭包持续持有,每次调用都操作同一个引用,确保旧任务被清除、新任务被安排。