Typescript中闭包的原理 - 教程

news/2025/9/18 22:13:08/文章来源:https://www.cnblogs.com/lxjshuju/p/19099825

在 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.mzph.cn/news/907470.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CF2048H Kevin and Strange Operation

操作的自由度很大,打表可以发现限制操作的位置只增不减也是对的。 考虑怎么判断一个串 \(t\) 是否合法。 观察到对于一个位置 \(i\) 满足 \(s_i=0\),想要通过操作使 \(s_i\) 变为 \(1\),只需要 \(>i\) 的位置删掉…

Hadoop本地库加载问题分析与解决方案

主要问题分析 ​​本地库加载警告​​: WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable 这表明Hadoop无法正确加载本地优化库…

GO基础总结

环境搭建 基本语法 参见:https://www.cnblogs.com/vonlinee/p/19005628 工具链

Visual Studio 离线安装0x80131509

Visual Studio 2026在本月发布了,它最大的特点是集成了GitHub Copilot,内置AI编程,空了要尝尝鲜(使用过Visual Studio Code的Copilot,还是挺有用的)。目前,VS2022很少使用,像VS2012一样被跳过,主要使用VS2019…

dash 从入门到精通

dash 从入门到精通目录 官方地址:https://plotly.com/dash/ Github 开源地址:https://github.com/plotly/dash Dash 官方文档:https://dash.plotly.com/

Oracle备份恢复:backup as copy保留文件名不变化,只更改路径名

我们的文章会在微信公众号IT民工的龙马人生和博客网站( www.htz.pw )同步更新 ,欢迎关注收藏,也欢迎大家转载,但是请在文章开始地方标注文章出处,谢谢! 由于博客中有大量代码,通过页面浏览效果更佳。Oracle备份恢…

读书笔记:数据库中的预连接神器:位图连接索引

我们的文章会在微信公众号IT民工的龙马人生和博客网站( www.htz.pw )同步更新 ,欢迎关注收藏,也欢迎大家转载,但是请在文章开始地方标注文章出处,谢谢! 由于博客中有大量代码,通过页面浏览效果更佳。本文为个人学…

飞算JavaAI:专为Java开发者打造的智能编程革命 - 实践

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

故障处理:CRS无法随操作系统自动启动故障案例分享

我们的文章会在微信公众号IT民工的龙马人生和博客网站( www.htz.pw )同步更新 ,欢迎关注收藏,也欢迎大家转载,但是请在文章开始地方标注文章出处,谢谢! 由于博客中有大量代码,通过页面浏览效果更佳。今天分享一个…

02020401 EF Core基础01-EF Core简介和开发环境搭建、实体类、配置类、继承DbContex的类、Migration包的使用

02020401 EF Core基础01-EF Core简介和开发环境搭建、实体类、配置类、继承DbContex的类、Migration包的使用 1. EF Core简介(视频3-1)本课程需要你有数据库、SQL等基础知识。关系数据库:MySql、SQL Server、Oracle…

专用通路方式

-取址周期 1.从pc取址到mar (pc)->mar 此时c0有效 2.把刚才的值交给内存 (mar)->内存 c1 3.让内存读取mar中保存的值 1->r 4.让mdr获取内存刚刚读取的mar中保存的代码值 MEM(MAR)->MDR C2 5.再让IR(指令…

typeof()

C# 中的 typeof() 是啥?一句话讲清楚:typeof() 就是“问编译器:这个类型长啥样?”它不是运行时去查对象,而是编译时就确定你写的那个“类名、接口名、结构名”到底是谁,然后返回一个叫 Type 的对象,这个对象里装…

详细介绍:【C++】C++类和对象—(中)

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

【未完成】2025.9 做题记录

CF1310C CF616F CF1065G CF1536F. Omkar and Akmar *2600 题意 Alice 和 Bob 在一个 \(n\) 个格子的环上玩游戏,环上的格子编号为 \(1\sim n\)。 每一轮中,玩家可选择一个空格子填入字母 A 或 B,同时要求不能存在两…

【9月中】

【9月中】rating:1173 已经好几个月没更新近况了,期末月,暑假回来 3 场 XCPC 初体验,意料之外,未曾想过,受宠若惊,还是菜鸡,JXCPC 垫底,网络赛爆零 我到底为什么还要走这条路啊,明明没有希望,而且就算自己这…

08-分组函数

08-分组函数$(".postTitle2").removeClass("postTitle2").addClass("singleposttitle");介绍 分组函数的执行原则:先分组,然后对每一组数据执行分组函数。如果没有分组语句group by的…

Stanford CS336 | Assignment 1 - Transformer Language Model Architecture - 详解

Stanford CS336 | Assignment 1 - Transformer Language Model Architecture - 详解2025-09-18 21:47 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; ove…

2025.8 做题记录

P4064 [JXOI2017] 加法 蓝 题意 可怜有一个长度为 \(n\) 的正整数序列 \(A\),但是她觉得 \(A\) 中的数字太小了,这让她很不开心。 于是她选择了 \(m\) 个区间 \([l_i,r_i]\) 和两个正整数 \(a,k\)。她打算从这 \(m\)…

关于 “Thinking Machines Lab首次发长文” 的一些知识的学习和补充

1. 前言砚上三五笔,落墨鹧鸪啼原文链接: https://thinkingmachines.ai/ 相关分析链接:https://www.gongjiyun.com/blog/2025/9/fu1xw1spci9vnokjipecs9y9nzn/最近看到一篇名为《击败 LLM 推理中的非确定性:从“玄学…

python编程练习(Day4) - 教程

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …