前言
前面写过关于JavaScript的this指向的基础文章,链接:juejin.cn/post/751796…
今天我们继续来讲讲闭包的应用场景之一:IIFE
IIFE-立即执行函数
在讲实例前,先来回顾一下IIFE。
const Counter = (function (){
// 这里的代码会在定义时立即执行一次
// ...
})();
(function(){ ... })() 是一个 IIFE(Immediately Invoked Function Expression),意思是“定义后立即执行”。
不管调不调用Counter,IIFE在它被定义完成时就会执行一次。
举个简单例子来理解:
const foo = (function() {
console.log("IIFE 被执行了");
return function() {
console.log("我是返回的函数");
};
})();
// 输出:IIFE 被执行了
// 此时还没有调用 foo()
但 "IIFE 被执行了" 已经输出了 —— 因为 IIFE 在定义的时候就执行了!
实例
const Counter = (function (){
let count = 0; // 自由变量 私有
function increment (){
return ++count; // 闭包
}
function reset() {
count = 0; // 闭包
}
return function(){
return {
getCount: function(){ // 闭包
return count; // 闭包
},
increment: function(){
return increment(); // 闭包
},
reset: function(){
return reset(); // 闭包
}
}
}
})();
const counter1 = Counter();
const counter2 = Counter();
console.log(counter1.getCount()); // 0
counter1.increment();
console.log(counter2.getCount()); // 1
这段代码的执行顺序如下:
第一步:定义并立即执行一个匿名函数
(function (){ ... })()是一个 IIFE。- 这个函数在定义后立即执行,返回值赋给了
Counter。 - 所以此时
Counter并不是函数本身,而是这个 IIFE 返回的结果 —— 也就是它内部的一个函数。
第二步:IIFE 内部做了什么?
-
定义了一个局部变量
count = 0,这是私有变量,外部无法直接访问。 -
定义了两个函数:
increment():递增countreset():将count重置为 0
-
然后返回一个新的函数,这个函数每次被调用时会返回一个对象,对象中包含三个方法:
getCount():获取当前countincrement():调用内部的incrementreset():调用内部的reset
为什么这些函数能访问到 count?
因为它们都形成了 闭包,可以访问其外层作用域中的变量
count。
为什么会输出 0 → 1?
虽然看起来 counter1 和 counter2 是独立的,但实际上:
return function(){
return {
getCount: function(){ return count; },
increment: function(){ return increment(); },
reset: function(){ return reset(); }
}
}
这里的 count, increment, reset 都是在 IIFE 内部定义的,也就是说,所有的 Counter() 实例其实共享同一个 count 变量。
所以实际上:
counter1.increment()修改的是同一个countcounter2.getCount()获取的也是同一个count
结尾
IIFE内部定义的变量都是私有的,我们可以通过闭包来访问,这就是闭包的应用场景之一--IIFE。