当前位置: 首页 > 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

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

在底层,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.wxhsa.cn/company.asp?id=5348

相关文章:

  • IvorySQL 4.6:DocumentDB+FerretDB 实现 MongoDB 兼容部署指南
  • 在Xilinx Vitis中创建并使用静态库
  • Go使用cyclicbarrier示例
  • 做题记录2
  • 剑指offer-30、连续⼦数组的最⼤和
  • ITK-SNAP 安装
  • Morpheus 审计报告分享3:StETH 的精度丢失转账机制
  • 小区物业的智慧:轻松图解JVM垃圾回收的奥秘
  • SPI 总线概述及嵌入式 Linux 从属 SPI 设备驱动程序开发(第二部分,实践) - 教程
  • 详细介绍:idea2025创建第一个项目
  • CUDA多版本安装切换(转链接自用)
  • 社交交友源码:功能剖析、盈利探索与绿色运营策略
  • 权变与权力异化,是斗争的根源,超越自我,良性循环
  • 元推理AGI,是人类文明的结晶,超越爱因斯坦相对论,是文明进步的必然
  • PLC结构化文本设计模式——原型模式(Prototype Pattern)
  • 【一步步开发AI运动APP】十二、自定义扩展新运动项目1
  • 【Linux】人事档案——用户及组管理 - 详解
  • 试试这个AI邪修方法,让你刷推特时间节省80%
  • [数据结构——lesson10.2堆排序以及TopK障碍]
  • 终端里跑图形应用「GitHub 热点速览」
  • trl ppo
  • PHP-FPM 深度调优指南 告别 502 错误,让你的 PHP 应用飞起来
  • RAG系统大脑调教指南:模型选择、提示设计与质量控保一本通
  • 智驾终局:VLA与WA的“强脑”之争
  • 微软2018年第四季度顶级漏洞赏金猎人榜单揭晓
  • 能源汽车智能线控底盘
  • Linux中的LED子专业的系统
  • DP 凸性优化:wqs 二分
  • 浦东再添一所一流高校,上海交通大学医学院浦东校区正式启用
  • nccl study