💡 闭包的概念
闭包 = 函数 + 函数定义时的作用域(环境)
更通俗的说法:
- 当一个函数 能“记住”它定义时的环境,即使这个函数在别的地方执行,它也能访问那个环境里的变量。
- 闭包就是 JS 的一种 变量私有化和长期记忆机制。
🧩 类比生活场景
想象你在做 便签盒子:
- 你写了一个便签,写上“今天做的事情”。
- 便签放进盒子里,盒子记住了便签上的内容。
- 以后你可以随时打开盒子,看到原来写的内容,即使你离开了写便签的地方。
- 便签盒子 → 闭包
- 便签内容 → 局部变量
- 打开便签 → 执行函数访问变量
🔧 JS 示例
1️⃣ 简单闭包
function makeCounter() {
let count = 0; // 局部变量,只有 makeCounter 内部可访问
return function() {
count++; // 内部函数可以访问外部函数的变量
return count;
};
}
const counter = makeCounter(); // 创建闭包
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3
分析:
makeCounter执行一次,返回一个函数。- 返回的函数 记住了
count这个变量,即使外部makeCounter已经执行完了。 - 每次调用
counter()都可以访问并修改count。
2️⃣ 闭包的私有变量
闭包可以实现 变量私有化,外部无法直接修改变量:
function createPerson(name) {
let _name = name; // 私有变量
return {
getName: function() {
return _name;
},
setName: function(newName) {
_name = newName;
}
};
}
const person = createPerson("Logan");
console.log(person.getName()); // Logan
person.setName("Alice");
console.log(person.getName()); // Alice
分析:
_name对外部不可直接访问,只能通过getName和setName。- 闭包帮我们安全地管理内部状态。
3️⃣ 注意点
- 内存问题:闭包会让外部函数的局部变量一直存在,可能占用内存。
- 循环闭包陷阱:
for (var i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i); // 输出 3,3,3
}, 100);
}
// 用 let 就不会了
for (let i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i); // 输出 0,1,2
}, 100);
}
- 因为
var是函数级作用域,所有闭包共享同一个i。
💡 总结闭包的作用:
- 访问外部函数的变量
- 实现私有变量和方法
- 保持函数执行环境(记忆功能)
- 在异步或回调中保持状态