定义
IIFE(立即调用函数表达式)是一个在定义时就会立即执行的 JavaScript 函数。
(function () {
// …
})();
(() => {
// …
})();
(async () => {
// …
})();
它是一种设计模式,也被称为 “自执行匿名函数” ,主要包含两部分:
- 第一部分是一个具有词法作用域的匿名函数,并且用 “圆括号运算符
()” 运算符闭合起来。这样不但阻止了外界访问 IIFE 中的变量,而且不会污染全局作用域。 - 第二部分创建了一个立即执行函数表达式
(),通过它,JavaScript 引擎将立即执行该函数。
方便理解
(() => {
// ...
})()
上述自执行匿名函数,可以这样理解:
const test = () => {}
test()
模块模式
const makeWithdraw = (balance) => {
return ((copyBalance) => {
let balance = copyBalance; // 这个变量是私有的
const doBadThings = () => {
console.log("I will do bad things with your money.");
};
doBadThings();
return {
withdraw: function (amount) {
if (balance >= amount) {
balance -= amount;
return balance;
}
return "Insufficient money"
}
}
})(balance)
}
const firstAccount = makeWithdraw(100);// "I will do bad things with your money"
console.log(firstAccount.balance); // undefined
console.log(firstAccount.withdraw(20)); // 80
console.log(firstAccount.withdraw(30)); // 50
console.log(firstAccount.doBadThings); // undefined; this method is private
const secondAccount = makeWithdraw(20); // "I will do bad things with your money"
console.log(secondAccount.withdraw(30)); // "Insufficient money"
console.log(secondAccount.withdraw(20)); // 0
创建了私有变量 balance ,私有方法 doBadThings() 和 公共方法 withdraw()
Tip
当我们调用
makeWithdraw(100)时,返回的是一个IIFE,它会立即执行,而不用再调用firstAccount()。这个IIFE立即执行后,返回了Object对象,其中有一个属性withdraw。另一点需要注意的是这里有一个嵌套的闭包环境。即
firstAccount.withdraw保存了IIFE和最外层箭头函数的变量环境(var)和词法环境(let、const)。具体点就是参数balance。
for循环
let arr = new Array(2)
for (var i = 0; i < 2; i++) {
arr[i] = (function (copyOfI) {
return () => {
console.log(copyOfI);
};
})(i);
}
arr[0]()
在for循环中异步调用时,可以使用IIFE和闭包保存每次循环中i的值。当然使用let会更方便。
总结
-
在ES6之前,js的模块化基本就是靠IIFE和闭包实现的,就像上面提到的模块模式。ES6之后,有了export和import;也有了class语法糖,可以更方便的实现模块化。
-
IIFE一般和闭包一起使用,有以下三大特点:
- 立即执行
- 变量私有化
- 变量持久化