在闭包(二)中我们就了解过,严格来说,IIFE并不是闭包,因为他并不满足函数成为闭包的三个条件。但是一般的,人们认为IIFE就是闭包。
实现
函数跟随一对圆括号()表示函数调用
//函数声明语法
function test(){};
test();
//函数表达式
var test=function(){};
test();
但是有时需要在函数定义之后,立即调用该函数。这种函数就叫做立即执行函数,全称为立即调用的函数表达式IIFE。
注意:js引擎规定,如果function关键字出现在行首,一律解释成函数声明语句。
【1】函数声明语句需要一个函数名,由于没有函数名,所以会报错。
SyntaxError: Unexpected token (
function(){}();
【2】函数声明语句后面加上一对圆括号,只是函数声明语句与分组操作符的组合而已。由于分组操作符不能为空,所以报错。
//SyntaxError: Unexpected token )
function foo(){}();
//等价于
function foo(){};
();//SyntaxError: Unexpected token )
【3】函数声明语句加上一对有值的圆括号,也仅仅是函数声明语句与不报错的分组操作符的组合而已。
function foo(){}(1);
//等价于
function foo(){};
(1);
所以解决办法就是不要让function出现在行首,让引擎将其理解成一个表达式
(function(){ /* code */ }());
(function(){ /* code */ })();
用途
IIFE一般用于构造私有变量,避免全局空间污染
接下来用一个需求来更直观的说明IIFE的用途。假设有一个需求,每次调用函数,都返回加1的一个数字(数字初始值为0)
【1】全局变量
一般情况下,我们会使用全局变量来保存该数字状态。
var a = 0;
function add(){
return ++a;
}
console.log(add());//1
console.log(add());//2
【2】自定义属性上面的方法中,变量a实际上只和add函数相关,却声明为全局变量, 不太合适。将变量a改为函数的自定义属性更为合适。
function add(){
return ++add.count;
}
add.count = 0;
console.log(add());//1
console.log(add());//2
注意:
- 函数是一种特殊的对象,他可以拥有属性。
- 函数属性和函数内定义的变量不同,函数属性的作用域是和全局变量一样的,可以像全局变量一样被访问和修改,但是它不完全是全局变量。函数内定义的变量是局部变量,函数调用完成后就销毁。
- 当调用函数需要一个一直存在的值的时候,可以讲这个值存在全局变量中;也可以存在一个函数对象的属性中,调用这个函数就会返回这个值;
【3】IIFE
其实上面的方法还是有问题。有些代码可能会无意中将add.count重置。
使用IIFE把计数器变量保存为私有变量更为安全,同时也可以减少对全局空间的污染。
var add = (function(){
var counter = 0;
return function(){
return ++counter;
}
})();
console.log(add())//1
console.log(add())//2