立即调用函数表达式(IIFE)

86 阅读2分钟

定义

IIFE(立即调用函数表达式)是一个在定义时就会立即执行的 JavaScript 函数

(function () {
  // …
})();

(() => {
  // …
})();

(async () => {
  // …
})();

它是一种设计模式,也被称为 “自执行匿名函数” ,主要包含两部分:

  1. 第一部分是一个具有词法作用域的匿名函数,并且用 “圆括号运算符 () ” 运算符闭合起来。这样不但阻止了外界访问 IIFE 中的变量,而且不会污染全局作用域。
  2. 第二部分创建了一个立即执行函数表达式 (),通过它,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一般和闭包一起使用,有以下三大特点:

    • 立即执行
    • 变量私有化
    • 变量持久化