ECMAScript闭包

闭包是函数与其词法环境绑定后形成的可访问组合。

#type / concept #status / growing #resource / javascript #resource / ecmascript

[!info] related notes

ECMAScript闭包

闭包可以先记成一句话:函数把定义时可访问的词法环境一起带走了。

最短定义

  • 闭包不是单独一种语法,而是函数和其外层词法环境的组合
  • 只要函数在别处执行时,仍然能访问定义位置的变量,就已经进入闭包语境
  • 最常见形式是函数返回函数,但回调、事件处理器、模块工厂也都会产生闭包

它为什么成立

  • ECMAScript 使用词法作用域,变量可访问性由定义位置决定
  • 函数是一等对象,可以被返回、传递、保存
  • 只要内部函数还被引用,相关词法环境就可能继续存活

它主要解决什么

  • 保留跨调用的私有状态
  • 给回调保留创建时的上下文
  • 构造函数工厂、模块封装、柯里化等模式都依赖这种能力

最容易误解的点

  • 闭包不等于内存泄漏;问题在于不再需要的引用没有释放
  • 闭包捕获的是变量绑定,不一定是当时的值快照
  • 只背“return 一个内部函数”不够,重点是词法环境没有丢

一个最小例子

function makeCounter() {
  let count = 0;

  return function () {
    count += 1;
    return count;
  };
}

const next = makeCounter();

next(); // 1
next(); // 2

makeCounter() 已经执行结束,但返回的函数仍然能访问 count,这就是闭包最典型的表现。

这篇和相邻笔记怎么分工

面试要点

来自 curry-interview-question 的面试视角整理。

补充来自 javascript-closure-interview-question

一句话回答

闭包就是函数和其定义时可访问的词法环境形成的组合,因此函数即使在别处执行,仍然能访问外层变量。

面试回答主线

它为什么会出现

因为 JavaScript 使用词法作用域,而函数又能被返回、传递和保存。

它解决什么问题

  • 保存私有状态
  • 给回调保留上下文
  • 实现函数工厂、柯里化、模块封装

常见应用

  • 计数器
  • 防抖节流
  • 事件处理器
  • 模块私有变量

常见误区

闭包不等于内存泄漏

闭包本身不是问题,真正的问题是本该释放的引用一直被保留。

闭包捕获的是变量绑定

不是简单的值拷贝,这也是很多循环和异步题的关键。

最短记忆方式

闭包 = 函数把定义时的可访问环境一起带走了。

一句话回答

柯里化是把接收多个参数的函数,转换成多次接收部分参数的函数调用,直到收集齐所有参数后才执行。它依赖闭包保存历史参数。

面试回答主线

它解决什么问题

  • 参数预填:提前固定部分参数,生成更专用的函数
  • 延迟执行:参数没收集齐之前不执行,适合配置链式调用
  • 类型推导:在 TS 里可以更精确地约束每步参数类型

手写实现

最简版(固定两参数):

function add(a: number) {
  return function (b: number) {
    return a + b;
  };
}

console.log(add(2)(3)); // 5

通用版(任意参数,toString 触发求值):

function add(...args: number[]) {
  const sum = args.reduce((a, b) => a + b, 0);
  const fn = function (...more: number[]) {
    return add(...args, ...more);
  };
  fn.valueOf = () => sum;
  return fn;
}

console.log(+add(1)(2)(3)); // 6

和闭包的关系

柯里化内部必须用闭包保存已经接收的参数。每次返回的新函数都携带了之前的参数上下文。

实际应用

  • 函数组合compose / pipe 里常用柯里化让函数更容易串联
  • 事件处理const handleClick = (id) => () => { ... }
  • 配置函数:先传配置,再传数据,最后执行
  • React/Vue 场景:生成带预设参数的回调处理器

常见误区

柯里化不等于部分应用

  • 柯里化:严格地每次只接收一个参数,直到收集完
  • 部分应用:可以一次接收多个参数,返回剩余参数的函数

面试里如果题目是 add(1)(2)(3),通常期望的是柯里化风格。

不要只写代码不说思路

手写时先说”用闭包保存参数,判断参数是否收齐,收齐就执行,没收齐就返回新函数”,再写代码。

最短记忆方式

柯里化 = 分步收参数 + 闭包存历史 + 收齐再执行

创建于 2025/1/1 更新于 2026/5/27