前言
立即执行函数表达式(也称为自执行匿名函数)形式:
(function () {
//Code
})();
(function () {
//Code
}());
问题:普通函数的调用,我们都知道如何调用,那么匿名函数的调用,如何做呢?
//直接在匿名函数后边加()--方式A
function () {
console.log("f1");
}();
// SyntaxError: Unexpected token (
很不幸,出错了:// SyntaxError: Unexpected token (, 那试试前言中的方法:
//匿名函数外套一个(), 然后再用()来调用 --方式B
(function() {
console.log("test"); //test
})();
//在方式A的外层套一个() --方式C
(function() {
console.log("test"); //test
}());
为什么方式A不能运行,而B和C可以运行。原来,JavaScript解释器会在默认的情况下把遇到的function关键字当作是函数声明语句来进行解释的,而函数声明语句是这样的:
function name([param] [,param]) {
statements
}
显然A的调用方式有问题,所以才会报错。但是B,C方式为什么可以正常运行了?这是因为JavaScript中()之间只能包含表达式(expression),所以在B,C方式运行的时候,解释器把()中的内容当作表达式(expression)而不是语句(statement)来执行。为了能够更好的解释B, C调用方式,在这里插入对()操作符简单的介绍:
// 如果传入字面量(literal), 则返回表达式
(1) //1
(function(){console.log("123");}) // function () {console.log("123");}
我们先分析B的调用方式:由于把函数的声明卸载了()之中,所以解释器以表达式(expression)来解释其中代码,而根据我们上面的介绍知道,如果向()中传入函数声明会直接返回此函数,此步执行完成之后,临时结果用伪代码来表示的话,应该类似这样:
anonymousFunction();
这个就是函数的通用调用方式,所以继续执行。对于C的调用方式就更加容易理解了,直接把()中的内容当作表达式来进行解释。
所以根据上面的解释,我们知道只要能让JavaScript解释器以函数表达式而不是函数声明来处理匿名函数的立即执行就可以,把语句放在()之中只是其中方法之一而已,根据这个思路,我们可以用其他方式来实现统一的目的,比如:
// 如果本身就是expression,那么根本不需要做任何处理
var i = function(){ return 10; }();
true && function(){ /* code */ }();
0, function(){ /* code */ }();
// 如果你不在乎返回值,可以这么做
!function(){ /* code */ }();
~function(){ /* code */ }();
-function(){ /* code */ }();
+function(){ /* code */ }();
// 还有更奇葩的方式,但是不知道性能如何,来自
// http://twitter.com/kuvos/status/18209252090847232
new function(){ /* code */ }
new function(){ /* code */ }()
为什么使用立即执行函数表达式
1 模拟块作用域
例如:
//liba.js中
var num = 1;
...
//libb.js中
var num = 2;
...
如果在页面中同时引用liba.js 和 libb.js 两个库,必然导致num变量被覆盖,为了解决这个问题,可以通过IIFE来解决:
//liba.js
(function(){
var num = 1;
// code....
})();
//libb.js
(function(){
var num = 2;
// code....
})();
经过改造之后,两个库的代码就完全独立,并不会互相影响。
解决闭包冲突
详情请见系列文章——闭包
模拟单例
var counter = (function(){
var i = 0;
return {
get: function(){
return i;
},
set: function( val ){
i = val;
},
increment: function() {
return ++i;
}
};
}());
counter.get(); // 0
counter.set( 3 );
counter.increment(); // 4
counter.increment(); // 5
参考文献
http://weizhifeng.net/immediately-invoked-function-expression.html
网友评论