javascript自执行函数

起因,今天在豪大大的JS开发群里有人问了一道题,

1
2
3
4
5
6
7
8
9
10
11
12
var test=(function(a){
this.a = a;
return function(b){
return this.a.e + this.a.f + b;
}
}(function(a,b){
return{
e:a,
f:b
};
}(1,8)));
console.log(test(4));

对此有点似懂非懂,于是就查阅了一番。
( function(){…} )()和( function (){…} () )是两种javascript立即执行函数的常见写法,最初我以为是一个括号包裹匿名函数,然后再在后面加个括号调用函数,最后达到函数定义后立即执行的目的,后来查看资料发现并非如此。要理解立即执行函数,需要先理解一些函数的基本概念。
函数声明、函数表达式、匿名函数,立即执行函数

函数声明(Function Declaration)的典型格式

1
2
function fun(){
}

函数表达式(Function Expression)的典型格式

1
2
var fun=function(){
}

匿名函数function () {}; 使用function关键字声明一个函数,但未给函数命名,所以叫匿名函数

立即执行函数(Immediate Functions)的典型格式

1
2
3
(function(){
alert('watchout!');
}());

这种定义匿名函数并立即在单个表达式中调用的写法非常常见,已经成为一种惯用法了。注意上面代码圆括号的用法,function之前的左圆括号是必须的,因为如果不写这个左圆括号,Javascript解析器会试图将关键字function解析为函数声明语句。使用圆括号Javascript解析器才会正确的将其解析为函数定义表达式。使用圆括号是习惯用法,尽管有其他的不同表达方式。
可以看到将函数声明转换成函数表达式有多种不同方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
(function(a){
console.log(a);//输出123,使用()运算符
})(123);
(function(a){
console.log(a);//输出1234,使用()运算符
}(1234));
!function(a){
console.log(a);//输出12345,使用!运算符
}(12345);
+function(a){
console.log(a);//输出123456,使用+运算符
}(123456);
-function(a){
console.log(a);//输出1234567,使用-运算符
}(1234567);
var fn=function(a){
console.log(a);//输出12345678,使用=运算符
}(12345678)

关于立即执行函数的返回值
就像其它任何函数一样,一个立即执行函数也能返回值并且可以复制给其它变量

1
2
3
4
5
6
var result=(function(){
return 1+2;
}());
var result=function(){
return 1+2;
}();

这两个实现的功能是一样的。
这种语法是非常简单的,但它可能看起来有点令人误导; 如果没有注意到函数结束的括号,
一些人可能就会认为result指向一个函数; 实际上result指向立即执行函数的返回值,在这种情况下是数字 3 。
如下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var test=(function(){
var i= 0;
return{
get:function(){
return i;
},
set:function(val){
i = val;
},
increment:function(){
return ++i;
}
};
}());
test.get();//0
test.set(3);
test.increment();//4

再返回到最开始

1
2
3
4
5
6
7
8
9
10
11
12
var test=(function(a){
this.a=a;
return function(b){
return this.a.e + this.a.f + b;
}
}(function(a,b){
return{
e : a,
f : b
};
}(1,8)));
console.log(test(4));

可以把

1
2
3
4
5
6
function(a,b){
return{
e : a,
f : b
};
}(1,8)

看作一个整体,返回

1
2
3
4
{
e : 1,
f : 8
}

return this.a.e + this.a.f + b;
就是1+8+4 = 13了。

有错误的地方欢迎拍砖

参考
汤姆大叔的博客
JavaScript权威指南