JavaScript中 说说你对闭包的理解?闭包使用场景?
第一步:想象一个时光机
假设你有一个「时光机函数」,它能创造一个小盒子:
function 时光机() {const 秘密 = "2023年的记忆"; // 外部变量(时光胶囊里的内容)function 小盒子() { // 内部函数(时光胶囊)console.log(秘密); // 访问外部变量}return 小盒子; // 把胶囊抛向未来
}const 未来胶囊 = 时光机(); // 执行时光机,现在时光机函数已经结束运行了
未来胶囊(); // 输出:"2023年的记忆" (即使时光机消失了,胶囊里的记忆还在!)
关键点:
- 时光机函数:创建时就决定了胶囊里的内容(外部变量)。
- 小盒子函数:像时空胶囊,把当时的记忆(变量)保存下来。
- 未来调用:即使外部函数(时光机)早已消失,内部函数(胶囊)依然能记住当时的变量。
闭包的本质:两件套
- 外层函数:提供「要被记住的变量」。
- 内层函数:像胶水一样粘住这些变量,不让它们被销毁。
闭包使用场景:3 个经典案例
场景1:计数器(保存状态)
function 创建计数器() {let 计数 = 0; // 这个变量会被闭包记住return function() {计数++;console.log(计数);};
}const 计数器A = 创建计数器();
计数器A(); // 1 (每次调用都记住最新的计数)
计数器A(); // 2 const 计数器B = 创建计数器();
计数器B(); // 1 (B的计数是独立的)
- 类比:每个计数器都是独立的「魔法沙漏」,自己记录时间。
场景2:私有变量(数据隐藏)
function 创建银行账户(初始金额) {let 余额 = 初始金额; // 外部无法直接访问return {存钱: (金额) => 余额 += 金额,查余额: () => `当前余额:${余额}元`};
}const 我的账户 = 创建银行账户(100);
我的账户.存钱(50);
console.log(我的账户.查余额()); // "当前余额:150元"
console.log(我的账户.余额); // undefined (无法直接访问)
- 类比:银行金库(闭包)保护你的钱,只允许通过指定方式操作。
场景3:循环中的陷阱与修复
问题代码:
for (var i = 1; i <= 3; i++) {setTimeout(() => console.log(i), 1000);
}
// 输出:4,4,4 (不是预期的1,2,3)
原因:所有 setTimeout
共享同一个 i
(最终值4)。
闭包解法:
for (var i = 1; i <= 3; i++) {(function(当前值) { // 用闭包捕获每次循环的i值setTimeout(() => console.log(当前值), 1000);})(i);
}
// 输出:1,2,3
- 类比:给每次循环拍张快照,保存当时的数值。
闭包注意事项:内存问题
- 风险:如果闭包长期持有大对象(如 DOM 元素),可能导致内存无法释放。
- 解决:不再需要时手动解除引用:
let 工具 = 创建大型工具(); 工具.使用(); 工具 = null; // 告诉浏览器可以回收内存了
终极总结
- 闭包是什么:函数 + 它出生时的环境变量。
- 核心作用:保存状态、隐藏数据、创建独立空间。
- 一句话记忆:闭包让函数变成「带着记忆的魔法胶囊」✨