说清楚【闭包】

闭包的铁律,不管是在 TypeScript、JavaScript、Java 还是 Python 里,只要叫“闭包”,就必须满足这个核心条件:

一个函数(内部函数),被返回(或传递)到了它的作用域之外,并且它引用了外部的变量。

如果没有“返回函数”(或者把函数传给别的变量/回调),那就只是普通的“局部变量访问”,根本构不成闭包。

为什么必须返回函数?

咱们拆解一下逻辑,你就明白了:

如果不返回函数(普通情况)
function test() {
let count = 0;
count++;
console.log(count); // 输出 1
// 函数结束,count 变量直接销毁,没人能再碰到它了
}
test();
test(); // 再次调用,count 重新从 0 开始,输出 1

结果:每次调用都是全新的,count 存不住。
原因:因为没有把“能操作 count 的那个函数”交出去,count 随着 test 的结束就灰飞烟灭了。

只有返回了函数(闭包情况)
function makeCounter() {
let count = 0; // 外部变量

// 【关键】返回了一个内部函数
return function() {
count++; // 内部函数引用了外部变量
console.log(count);
};
}

const counter = makeCounter(); // 1. makeCounter 执行完,本该销毁 count
// 2. 但因为返回的函数还要用 count,JS 引擎强行保住了 count
counter(); // 输出 1 (count 还在!)
counter(); // 输出 2 (count 还在累加!)

结果:count 居然活下来了,而且还能被修改。
原因:因为你把那个能访问 count 的函数(return function...)扔到了外面(赋值给了 counter)。为了能让这个扔出去的函数正常工作,JS 引擎被迫把 count 也一起“打包”带走了。

哪怕不写 return,也是变相的“返回/传递”

有时候你可能没写 return function,但你把函数传给了别人,这也是闭包。本质还是函数跑出了它原本的家。

例子:定时器
function setupTimer() {
let seconds = 0;

// 这里没有 return,但是我把这个匿名函数传给了 setTimeout
// 这个匿名函数“逃跑”到了 setTimeout 的内部去执行
setInterval(() => {
seconds++;
console.log(seconds);
}, 1000);
}

setupTimer();
// 即使 setupTimer 执行完了,seconds 依然活着,因为那个匿名函数(闭包)还在运行

这里虽然没有 return,但箭头函数 () => { ... } 被传递给了 setInterval。
只要函数离开了它定义时的作用域,并且带着外部变量,它就是闭包。

总结

判断 TS 里是不是闭包,只需问两个问题:

有没有一个内部函数?
这个内部函数是不是“跑”到了外面去执行(通过 return 返回,或者作为参数传给其他函数),并且它还在用外面的变量?

如果是 rightarrow 闭包。
如果否(比如你的图片里,只是算个字符串返回,没有函数跑出来) rightarrow 普通函数。

所以,“返回(或传递)函数”是闭包存在的唯一前提。 没有这个动作,变量就留不住。

posted @ 2026-03-16 09:33  认真的刻刀  阅读(20)  评论(0)    收藏  举报