当前位置: 首页 > news >正文

Typescript中闭包的原理 - 教程

在 TypeScript(以及 JavaScript)中,闭包描述了函数能够访问其声明时所在作用域的变量,即使该函数在其声明的作用域之外被调用的现象。

定义:闭包是指一个函数能够记住并访问其词法作用域(lexical scope)中的变量,即使这个函数是在其词法作用域之外执行。

闭包的核心原理

  1. 作用域链机制:

    • 每个函数在创建时都会形成一个作用域
    • 当函数内部访问变量时,会先在自身作用域查找,如果找不到则向上级作用域查找,直到全局作用域
    • 这种层级关系形成了作用域链
  2. 函数与作用域的绑定:

    • 闭包的本质是函数与其声明时所处的词法环境(lexical environment)的组合
    • 当函数被创建时,会捕获(close over)其周围的变量和函数,形成一个封闭的环境
  3. 延长变量生命周期:

    • 正常情况下,函数执行完毕后,其内部变量会被垃圾回收
    • 但如果存在闭包引用了这些变量,它们会被保留下来,直到闭包不再被引用

TypeScript 中的闭包示例

function outerFunction(message: string) {
// 这个变量会被内部函数捕获
const count = 0;
// 内部函数形成闭包
function innerFunction() {
// 可以访问outerFunction的变量
console.log(message);
console.log(count);
}
// 返回闭包
return innerFunction;
}
// 接收闭包
const closure = outerFunction("Hello, Closure!");
// 即使outerFunction已执行完毕,仍能访问其内部变量
closure(); // 输出: "Hello, Closure!" 和 0

闭包的用途

  1. 数据私有化:创建私有变量和方法
  2. 函数工厂:根据参数生成不同功能的函数
  3. 回调函数:在异步操作中保持状态
  4. 模块模式:实现模块化代码

TypeScript 对闭包的增强

TypeScript 作为 JavaScript 的超集,完全支持闭包特性,并且通过类型系统增强了闭包的使用:

function createCounter(initial: number): () => number {
let count = initial;
return function(): number {
return count++;
};
}
// 类型推断会正确识别返回的函数类型
const counter = createCounter(10);
console.log(counter()); // 10
console.log(counter()); // 11

实例

让我们看一个用 TypeScript 编写的经典例子:

function outerFunction(outerValue: number) {
// 外部函数的变量
const outerString: string = "Hello";
// 内部函数 -> 闭包开始形成
function innerFunction(innerValue: number): void {
console.log(`Outer value: ${outerValue}`);
console.log(`Outer string: ${outerString}`);
console.log(`Inner value: ${innerValue}`);
console.log(`Total: ${outerValue + innerValue}`);
}
// 返回内部函数,使其能够在 outerFunction 的作用域外被执行
return innerFunction;
}
// 调用 outerFunction,它返回 innerFunction
// 此时,closure 就是一个闭包实例,它“关闭”了 outerFunction 的作用域
const closure = outerFunction(10);
// 在 outerFunction 的执行上下文已经销毁后,调用 closure
// 但是 closure 仍然能访问到 outerValue 和 outerString
closure(5); // 输出:
// Outer value: 10
// Outer string: Hello
// Inner value: 5
// Total: 15

原理深入剖析:执行上下文与词法环境

在底层,JavaScript 引擎通过执行上下文和词法环境来实现闭包。

  1. 调用 outerFunction(10):

    • 创建一个新的执行上下文,并将其推入调用栈。

    • 创建对应的词法环境,其中包含了参数 outerValue 和局部变量 outerString

    • 定义 innerFunction。此时,innerFunction 的内部属性 [[Environment]] 会被设置为当前(即 outerFunction 的)词法环境的引用。这一步至关重要,它建立了作用域链的连接。

  2. outerFunction 执行完毕:

    • 其执行上下文从调用栈中弹出。

    • 但是,因为返回的 innerFunction 的 [[Environment]] 仍然引用着 outerFunction 的词法环境,所以这个词法环境不会被垃圾回收机制销毁。它被保留在内存中,以便 innerFunction 将来使用。

  3. 调用 closure(5) (也就是 innerFunction(5)):

    • 为 innerFunction 创建一个新的执行上下文和词法环境。

    • 这个新词法环境的外部环境引用指向的就是之前在 [[Environment]] 中保存的那个 outerFunction 的词法环境。

    • 当 innerFunction 尝试访问 outerValue 或 outerString 时,引擎会沿着这条作用域链查找,成功在 outerFunction 的词法环境中找到它们。

理解闭包有助于编写更优雅、更模块化的代码,但也要注意过度使用可能导致的内存问题,因为被闭包引用的变量不会被垃圾回收机制回收。

http://www.gsyq.cn/news/7624.html

相关文章:

  • Hadoop本地库加载问题分析与解决方案
  • 专用通路方式
  • 2025.8 做题记录
  • 关于pytorch的读书报告
  • Emacs 折腾日记(三十)——打造C++ IDE 续
  • 完整教程:.NET驾驭Word之力:玩转文本与格式
  • 综合与实现流程【p3】--(DSP-存储)优化PS系统集成
  • Docker 常用命令详解与参数说明 - 教程
  • 06-排序操作
  • Java运行机制
  • 除自身以外数组的乘积-leetcode
  • rapidXML解析xml文件
  • 大学不止GPA
  • 福昕PDF编辑器专业版破解 v2025 中文版安装使用教程
  • python 架构专业的技术50
  • 本地VMware Workstation Pro的rhel-server-7.9-x86_64服务器配置本地源
  • SCPI 标准命令
  • 前端,真的让我深刻感受到信息闭塞的恐怖 - 指南
  • 2025年十大AI网站构建工具:专家评测与推荐!
  • VulkanAPI细节梳理1
  • 意大利 公证 海牙认证速度 单号 双号
  • Linux命令学习笔记
  • 详细介绍:(附源码)基于Web的《药谷奇遇记》网站设计与实现-计算机毕设 72940
  • 想成为AI绘画高手?打造独一无二的视觉IP!Seedream 4.0 使用指南详解,创意无界,效率翻倍!
  • AI Compass前沿速览:Nano Bananary、MCP Registry、通义DeepResearch 、VoxCPM、InternVLAM1具身机器人
  • day12-Trae之一键换脸APP开发02
  • 详细介绍:今日分享 KMP算法
  • 线性回归与 Softmax 回归核心内容总结 - 教程
  • P6631 [ZJOI2020] 序列 题解
  • 使用 libaudioclient 实现 Android Native层 音频测试工具