javascript自调函数
Posted on 2016-02-25 in javascript by yucongchen
JavaScript中匿名函数一种非常常见的用法就是自调函数,这种函数可以在定义之后自行调用。
自调函数常见形式是:
(function(){
alert("foo");
})()
光看这个形式,可能会让人以为是在函数体前后包个括号,然后后面通过括号运算符来立即调用函数,形式上说是对的,但是为什么要给函数包个括号?下面我们就来重新认识一下自调函数。
要理解自调函数,首先我们要理解两个概念
函数声明
函数声明通常由一下几部分组成:
- function子句
- 函数名称
- 函数的参数
- 函数体
- return子句,默认返回值为undefined。
例子:
function foo(a,b) {
return a+b;
}
函数表达式
函数声明容易理解,函数表达式就陌生多了。其实,这里说的函数表达式,顾名思义就是一种表达式,内容是函数。表达式就是那些个加减乘除之类的。
比如说下面这个例子:
var foo = function (a,b) {
return a+b;
};
例子中,创建了一个匿名函数,然后把这个匿名函数的引用给了foo
这个变量。 严格来说,这个例子不完全是函数表达式,去除var foo
之后,剩下的就是一个函数表达式。
上面的例子要如何调用函数?很明显foo(1,2)
就可以了,之前说过foo
不过是那个匿名函数的引用,对foo使用括号运算符就可以调用这个匿名函数了。
既然如此,是不是也可以这样调用:
d = function (a,b) {
return a+b;
}(1,2)
这里变量d的值是3,因为此处等号是个二元运算符,所以看的可能不是太清楚,可以尝试改成如下形式:
+ function (a,b) {
return a+b;
}(1,2)
控制台中运行会输出3,这就是一个自调函数。
重新认识自调函数
分清楚函数声明和函数表达式之后,我们来重新认识自调函数。
先看几个例子:
(function(a){
console.log(a); //123
})(123);
(function(a){
console.log(a); //123
}(123));
! function(a){
console.log(a); //123
}(123);
+ function(a){
console.log(a); //1234
}(123);
- function(a){
console.log(a); //123
}(123);
void function(a){
console.log(a); //123
}(123)
可以看出,要让匿名函数自调用,首先要把匿名函数变成函数表达式,而不能是函数声明。
而把函数声明变成函数表达式的方法就是在function
关键字前面加点什么东西,例如括号,+,-,!,void,=,逗号,~……告诉js解析引擎,这个是一个函数表达式,可以通过()
运算符来执行。
而加()
是最安全的做法,因为加减号会影响返回值,而void
会让返回值为undefined
,所以括号用的最广泛,但我们要知道除了括号,别的也能实现自调函数。
自调用函数解决setTimeout传参数
有时候我们需要循环设置setTimeout
,并且每次执行的函数的参数还不一样,这个时候就是我们的自调函数大显身手的时候了:
var i = 0, tmp = [1,2,3];
for(i,len=tmp.length;i<len;i++) {
setTimeout(
(function(txt){
return function(){
console.log(txt)
}
})(tmp[i]),
1000*i);
}
控制台执行,可以看到依次打印出1,2,3
理解一下上面setTimeout
的执行:
- setTimeout里面把(function(){})()当成函数表达式执行,返回了一个匿名函数的引用;
- 当延时结束的时候,由js解释器来执行这个函数引用。
这里要注意,返回的是函数的引用,不要单纯的理解为字符串的传递。
参考资料
http://dengo.org/archives/1004
https://segmentfault.com/q/1010000002867883