闭包 知识点初探
通过理解函数嵌套结构、作用域链保留机制和内存管理特性,可以快速掌握闭包的核心逻辑。
一、作用
- 闭包让函数可以 “记住” 并持续访问其外层函数的变量,即使外层函数已经执行完毕。
- 闭包概念很有用只不过这个例子不恰当,不是让外部访问内部的变量,主要是让内部的函数可以有一些可以记录状态的变量,内部函数不需要立即执行.
- 闭包最大的作用是为了在外层函数执行完毕,不在调用栈了,内部函数依然能保持对变量使用
- 你们如果觉得这里没什么用就大错特错了,我是一个渗透测试人员,你如果不注重这个,我可以很容易的攻陷你的前端验证
- 也就是给了一个数据 全局变量不被自动回收的属性 以及 局部变量不能被外部修改的属性
典型应用场景
- 数据封装
function 计数器() {
let count = 0;
return {
增加: () => count++,
获取: () => count
};
}
const counter = 计数器();
counter.增加(); // 1
counter.增加(); // 2
- 回调函数
setTimeout(() => {
console.log("延迟执行"); // 闭包保留外部上下文
}, 1000);
- 模块化
const 模块 = (() => {
let 私有变量 = 0;
return { 公开方法: () => 私有变量++ };
})();
二、格式
- 注意了 return fn 没加括号 不是把fn函数执行一遍
- 相当于把最里层的函数的逻辑提到外面来了。这里是简单方便理解,函数封闭起来有的时候是为了安全考虑
- 理解了,你可以在return 函数中写你的逻辑,return的函数需要用到外层的变量。到时候全局接收后直接调用即可。而不是要获取值
- 因为下面return了,所以count()存的是里面的函数,最外面fun()调用也是count()里面的函数
闭包的格式本质
闭包的格式是函数(内外)嵌套+变量捕获:
function 外部函数() { // 1. 外层函数:定义变量并返回内层函数
let 外部变量 = 10;
return function 内部函数() { // 捕获外部变量 // 2. 内层函数:使用外层变量形成闭包
console.log(外部变量); // 使用外部变量
}
}
const 闭包实例 = 外部函数(); // 保存外部变量
闭包实例(); // 输出10 // 3. 闭包实例:保存外层变量的引用
三、原理
-
本质就是,函数名也是个地址,把地址赋予给其它变量,因此也可以直接调用函数
-
现在直接用那个变量就相当于你用里面的那个函数建立起用里变量的作用了
-
【红字大佬】原本我们想要实现一个计数功能,我们是不是得借助一个全局变量?次数加一,全局变量加1。那现在有了闭包我们能怎么样?我们能直接访问函数内部的那个变量,我们让函数内部的那个变量
接上条红色弹幕:实在不理解就看作是outer() //这一大坨是函数 () //这个括号是调用前面那个函数 -
函数结束后,局部变量会销毁,正常来说就不能再访问,但是js开了洞,在返回的函数里面保存了局部变量的副本,这个特性叫做闭包。
(一)闭包的原理分层
1.词法作用域: 函数定义时确定作用域,而非执行时。闭包通过函数定义时的作用域链保留变量。
2.内存管理
○ 外部函数执行后,其变量对象本应销毁
○ 闭包的存在使变量对象被保留(通过引用计数)
3.执行过程

(二)闭包与作用域的关系
(JS的闭包是为了给作用域链的反方向做补充,可以这么理解吗?)
不完全准确。闭包并非作用域链的"反方向补充",而是利用作用域链的静态特性实现变量持久化。闭包的核心在于通过保留词法作用域的引用,使函数即使在外部执行时仍能访问定义时的变量环境。
具体来说:
作用域链是自内而外的变量查找路径(当前→外层→全局)
闭包通过保留作用域链的引用,突破常规的"执行上下文销毁即回收"规则
闭包的本质是词法作用域的延伸而非反向,它维持了作用域链中变量对象的生命周期
function outer() {
const x = 10;
return function inner() { // 闭包保留对outer作用域的引用
console.log(x); // 沿作用域链查找x
}
}
const innerFunc = outer(); // outer执行完毕,但x仍被闭包保留
innerFunc(); // 输出10
这里闭包通过作用域链访问x,但作用域链本身仍是自内而外的查找路径,闭包只是延长了变量对象的存活时间。
(三)常见误区
1.内存泄漏: 闭包会保留外部变量,需手动解除引用:
let 闭包 = createClosure();
闭包 = null; // 释放内存
2.循环陷阱
for(let i=0; i<5; i++){ // 使用let创建块级作用域
setTimeout(() => console.log(i), 1000); // 正常输出0-4
}
四、对闭包属性的理解(待整理)
Q:闭包 给了一个数据 全局变量不被自动回收的属性 以及 局部变量不能被外部修改的属性。可以这么理解吗?
不完全准确,需要修正理解:
闭包的核心特性是:
1.保留外部函数作用域(非全局变量)
2.隔离外部访问权限(非禁止修改)
正确理解:
1.全局变量不受闭包影响: 闭包保护的是外部函数的局部变量,而非全局变量。全局变量本身就存在于全局作用域,不会被闭包自动保留。
2.局部变量被闭包"冻结": 外部函数的局部变量被闭包引用后,无法通过常规方式从外部修改,但闭包内部可通过nonlocal声明修改(如计数器场景)。
示例说明:
function 外部函数() {
let 外部变量 = 10; // 局部变量(非全局)
return {
get: () => 外部变量, // 只读访问
set: (val) => { 外部变量 = val } // 允许内部修改
};
}
const 闭包实例 = 外部函数();
闭包实例.set(20); // 允许修改
console.log(闭包实例.get()); // 输出20
关键区别:
| 特性 | 全局变量 | 闭包局部变量 |
|---|---|---|
| 生命周期 | 始终存在 | 依赖闭包引用 |
| 访问权限 | 全局可读写 | 闭包内可控 |
| 内存管理 | 常驻内存 | 引用存在则保留 |
常见误区:
- ❌ 闭包不会阻止全局变量回收
- ✅ 闭包会阻止外部函数局部变量回收
- ✅ 闭包可通过方法暴露修改接口(如
set方法)
通过这种机制,闭包实现了数据封装和私有变量保护,而非全局变量保护。
(有序 单句 为弹幕区内容)

浙公网安备 33010602011771号