JavaScript允许使用内部函数---即函数定义和函数表达式位于另一个函数的函数体内。而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数和声明的其他内部函数。当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包。
一、闭包的本质定义
闭包是通过函数嵌套 函数来实现的。内部函数可以访问外部函数的变量,既是外部函数已经执行完毕。
function outer() {
let secret = 123;
return function inner() {
console.log(secret); // 访问外部变量
};
}
const fn = outer();
fn(); // 123(仍能访问已销毁的outer作用域)
二、核心运行机制
-
作用域链保留:函数定义时捕获外层环境引用
-
生命周期延续:内部函数存在则外部变量不回收
-
动态访问:闭包变量可实时获取最新值
三,闭包的应用场景
1. 模块模式
const counter = (() => {
let count = 0;
return {
add: () => ++count,
get: () => count,
reset: () => count = 0
};
})();
counter.add();
console.log(counter.get()); // 1
2. 私有变量封装
function Person(name) {
let _age = 0;
return {
getName: () => name,
setAge: age => _age = age,
getInfo: () => `${name}(${_age})`
};
}
const p = Person('Alice');
p.setAge(25);
console.log(p.getInfo()); // Alice(25)
3. 循环陷阱解决方案
for(var i=0; i<3; i++) {
(function(j) {
setTimeout(() => console.log(j), 100);
})(i);
}
// 输出 0 1 2(不用闭包会输出3次3)
四,性能优化技巧
// 优化前:每次调用创建新闭包
function heavy() {
const data = new Array(1000000);
return () => data.length;
}
// 优化后:复用闭包
const light = (() => {
const cache = new Map();
return key => {
if(!cache.has(key)) {
cache.set(key, new Array(1000000));
}
return cache.get(key).length;
}
})();
箭头函数简化闭包:
const createAdder = x => y => x + y;
const add5 = createAdder(5);
console.log(add5(3)); // 8
五,注意
-
内存占用:
-
闭包可能会
-
导致一些内存占用问题,
-
-
特别是当他们引用大量数据时。
-
确保适当的管理这些引用
避免内存泄漏
-
垃圾回收:
-
现代JavaScript引擎(如V8)
-
会尝试优化闭包的内存管理,
-
但在编写代码时 仍需注意避免不必
-
要的闭包使用
-
性能:
-
在某些情况下,
-
频繁使用闭包可能会轻微影响性能,
-
尤其是在循环或频繁调用时。尽量避免不
-
必要的闭包可以提高性能