闭包
什么是闭包
闭包
定义:
函数嵌套,内部函数总是能够记录访问外部函数的函数作用域里的变量的一种特性
条件:
- 函数嵌套,外部函数,内部函数
- 内部函数引用了外部函数的变量
- 内部函数被保留(返回、传入、或赋值给全局变量)
词法环境
每个函数被调用或代码块执行时,都会创建对应的执行上下文,其中包含一个词法环境。词法环境用于记录当前作用域内的所有变量、函数声明,以及对外部词法环境的引用。当代码块执行完成且内部函数未被外部引用时,词法环境会被垃圾回收。
词法环境的核心作用是维护作用域链:它记录当前作用域的所有变量,同时保存对外部词法环境的引用。查找变量时,先在当前词法环境中查找,找不到则沿外部词法环境逐级向上查找,直至全局词法环境。这种链式查找机制称为作用域链。
全局环境就是全局词法环境。
当内部函数被外部保留时(如作为返回值、参数传递或赋值给全局变量),其词法环境会被保留,即使外部函数已执行完毕。这就是闭包能够持续访问外部函数变量的根本原因。
闭包优缺点
| 优点 | 说明 |
|---|---|
| 变量私有化 | 创建无法被外部直接访问的私有变量 |
| 避免全局污染 | 变量存在函数内部,不会挂载到 window |
| 变量持久化 | 变量在函数执行结束后依然存活 |
| 状态保持 | 多次调用同一函数,能记住之前的状态 |
| 函数工厂 | 动态生成定制化的函数 |
| 模块化 | 实现命名空间和代码隔离 |
js
function createCounter() {
let count = 0
return {
increment: () => ++count,
decrement: () => --count,
getCount: () => count
}
}防抖
状态保持
js
function debounce(fn, delay) {
let timer = null
return function (...args) {
if (timer) clearTimeout(timer)
timer = setTimeout(() => fn.apply(this, args), delay)
}
}节流
状态保持
js
function throttle(fn, delay) {
let lastTime = 0
return function (...args) {
const now = Date.now()
if (now - lastTime >= delay) {
lastTime = now
fn.apply(this, args)
}
}
}