在学习JavaScript的时候,经常会看到“自动立即执行的函数代码”。
说的通俗点就是:定义一个函数,然后立即调用它。
我们知道调用一个函数的方式是在函数名称后面添加一对圆括号。
例如:
var myFunction = function(){
//code
};
//立即执行上面定义的函数
myFunction();
上面的例子中,我们创建了一个匿名函数并把它赋值给一个变量myFunction。调用时该函数时,我们在变量名后面加一对圆括号,即myFunction();
因为在JavaScript中,变量只不过是值的一种表现形式,所以出现变量的地方也可以用值来替换。但当这个变量的值是一个匿名函数时,替换时就要注意。
关键点:1.JavaScript将function关键字当做一个函数声明的开始,而函数声明后面是不能直接加圆括号的。
2.JavaScript中,()圆括号里面是不能包含语句的。
利用上述两点,我们可以用一对圆括号将一个匿名函数的声明括起来,这样解析器在解析到function关键字时,就会将这个函数声明转换成一个函数表达式。所以上面的例子也可以改写成下面这样:
(function(){
//code
})();
或
(function(){
//code
}());
这个函数会自动立即执行。
这种“立即执行函数”的一个作用:模仿块级作用域。
JavaScript中是没有块级作用域的概念的。例如下面这个函数:
function output(count){
for(var i=0; i<count; i++){
alert(i);
}
alert(i);//还是打出count的值,变量i在这个函数内部随处可以被访问到
}
我们用“立即执行函数”和闭包把上面的函数改写一下,就可以得到我们想要的效果。
function output(count){
(function(){
//闭包,在output函数中创建了一个新的匿名函数,并访问了外部函数中的变量count
for(var i=0;i<count;i++){
alert(i);
}
})();
//alert(i);这时候就不能访问i了,因为i是在上面那个匿名函数中定义的变量,匿名函数执行完后,i就被销毁了。
}
这种“立即执行函数”的另一个作用:解决闭包作用链域的副作用,即闭包只能取得包含函数中任何变量的最后一个值。
例如下面这个函数,该函数返回一个函数数组,数组里的每个函数都返回自己的索引值。
function myFunction(){
var result = new Array();
for(var i=0; i<10; i++){
result[i] = function(){
return i;
};
}
return result;
}
var arr = myFunction();
alert(arr[1]()); //打出10
alert(arr[2]()); //打出10
上面这个函数并没有按我们的预期,函数返回后,每个result[i]的值都是10,因为闭包引用的都是同一个外部函数myFunction中的i。当外myFunction()函数返回后,变量i的值就是10。要达到预期效果,我们可以如下改写;
function myFunction(){
var result = new Array();
for(var i=0; i<10;i++){
result[i]= function(num){
return function(){
return num;
}
}(i);
}
return result;
}
var arr = myFunction();
alert(arr[1]()); //打出1
alert(arr[2]()); //打出1
在这里,我们增加了一个立即执行的匿名函数,并把立即执行的结果赋值给result数组,这时result数组中的每个函数都有自己的一个num副本,并且num副本的值每次执行匿名函数时都是不同的。