立即调用函数表达式 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 只存在于闭包)