立即执行函数

两种常见的立即执行函数写法:

1
2
3
(function(){}());

(function(){})();

以下是错误写法:

1
function(){}();

概念

在了解立即执行函数之前,学习一些概念:函数声明、函数表达式、匿名函数。

函数声明

1
function fnName(){};

声明一个有函数名的函数

函数表达式

1
var fnName = function(){};

声明一个没有函数名的函数,并将函数赋给一个变量

匿名函数

1
function(){}

声明一个函数,但该函数没有函数名

差异

一、js引擎在解析javascript代码时会‘函数声明提升’当前执行环境(作用域)上的函数声明,而函数表达式必须等到js引擎执行到它所在行时,才会从上而下一行一行地解析函数表达式。
举个例子

1
2
3
4
5
6
7
8
9
a();
function a(){
console.log('a');
};

b();
var b = function(){
console.log('b');
};

上述这段代码输出的结果是:

1
2
a
Uncaught TypeError: b is not a function(…)

使用函数声明生成的函数,可以在函数声明前就调用,而函数表达式则不行。

二、函数表达式后面可以加括号立即调用该函数,函数声明不可以,只能以fnName()形式调用。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
(function(a){
console.log(a);
}(123));

(function(a){
console.log(a);
})(124);

!function(a){
console.log(a);
}(125);

+function(a){
console.log(a);
}(126);

-function(a){
console.log(a);
}(127);

var fn = function(a){
console.log(a);
}(128);

以上都能成功输出结果。可以看到在function前添加特定的运算符都可以达到立即执行的效果。因为某些运算符可以消除js引擎识别函数表达式和函数声明的歧义,告诉javascript引擎这是一个函数表达式,不是函数声明。

作用

在多人开发时,为了避免污染全局环境,可以使用立即执行函数。根据js的函数作用域,函数内部可以访问函数外的的变量,而函数外则访问不了函数内的变量和方法。我们使用匿名函数创建了一个容器,我们在容器里的变量不会与外部变量冲突,相当于一个私有作用域。
看一个经典例子:

1
2
3
<button>1</button>
<button>2</button>
<button>3</button>
1
2
3
4
5
6
var btn = document.getElementsByTagName("button");
for(var i = 0; i < btn.length; i++){
btn[i].onclick = function(){
console.log(i);
};
}

刚开始学习都会以为依次输出0、1、2。其实结果是输出三次3。
解决办法则可以用到刚才说的立即执行函数。

1
2
3
4
5
6
7
8
var btn = document.getElementsByTagName("button");
for(var i = 0; i < btn.length; i++){
(function(i){
btn[i].onclick = function(){
console.log(i);
};
})(i);
}

更深入的以后再说喽。