Skip to main content

立即调用函数表达式 IIFE

一、什么是立即调用函数表达式

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

(function () {
statements
})();

1、IIFE 的一般写法

在 JavaScript 中,圆括号 () 是一种运算符,跟在函数名之后,表示调用该函数。比如,print() 就表示调用 print 函数。

有时我们需要在定义函数之后,立即调用该函数,例如:

function() {
/*code*/
} ()
// SyntaxError: Unexpected token (

以上代码出现了语法错误,因为 function 这个关键字即可以当作语句,也可以当作表达式。

// 语句
function f() { }

// 表达式
var f = function f() { }

JavaScript 引擎规定,如果 function 关键字出现在行首,一律解释成语句。

因此,上面错误的代码被认为这一段都是函数的定义,不应该以圆括号结尾,所以报错。

解决方法:不让 function 出现在行首,让引擎将其理解成一个表达式,例如将其放在一个圆括号里面。

// 解决方式一
(function () { /*code*/ }());

// 解决方式二
(function () { /*code*/ })();

以圆括号开头,JS 引擎就会认为后面跟的是一个表示式,而非函数定义语句,所以避免了错误。

注意,上面两种写法最后的分号都是必须的。如果省略分号,遇到连着两个 IIFE,会报错:

// 报错
(function () { /*code*/ }())
(function () { /*code*/ }())

这就是“立即调用的函数表达式”(Immediately-Invoked Function Expression),简称 IIFE。

2、IIFE 的其它写法

推而广之,任何让解释器以表达式来处理函数定义的方法,都能产生同样的效果,比如下面三种写法:

// 写法一
var i = function () { return 10; }();

// 写法二
true && function () { /*code*/ }();

// 写法三
0, function () { /*code*/ }();

甚至像下面这样写,也是可以的:

!function () { /*code*/ }();
~function () { /*code*/ }();
-function () { /*code*/ }();
+function () { /*code*/ }();

3、只对匿名函数使用 IIFE

通常情况下,只对匿名函数使用 IIFE,目的有两个:

  • 不必为函数命名,避免了污染全局变量。
  • IIFE 内部形成了一个单独的作用域,可以封装一些外部无法读取的私有变量。
// 写法一
var tmp = newData;
processData(tmp);
storeData(tmp);

// 写法二
(function () {
var tmp = newData;
processData(tmp);
storeData(tmp);
}());

上面代码中,写法二比写法一更好,因为完全避免了污染全局变量。

4、IIFE 的应用

在 JavaScript 的 OOP 中,可以通过 IIFE 来实现一个单例:

// 创建一个立即调用的匿名函数表达式
// return 一个变量,其中这个变量里包含你要暴露的东西
// 返回的这个变量将赋值给 counter,而不是外面声明的 function 自身

var counter = (function () {
var i = 0;

return {
get: function () {
return i;
},
set: function (val) {
i = val;
},
increment: function () {
return ++i;
}
};
}());

// counter 是一个带有多个属性的对象,上面的代码对于属性的体现其实是方法

counter.get(); // 0
counter.set(3);
counter.increment(); // 4
counter.increment(); // 5

counter.i; // undefined,因为 i 不是返回对象的属性
i; // 引用错误,i 没有定义(因为 i 只存在于闭包)