最近重学了一遍JavaScript关于闭包这一块的知识,收益颇多。所以想花点时间进行一个总结,接下来的几篇文章都会讲解关于闭包这一块的知识,闭包也是JavaScript中一大难点,牵扯到的知识点太多,今天就让我先来说说自执行函数和匿名函数吧。


什么是函数?

函数时JavaScript中最灵活也是最容易让人困惑的对象。定义函数方式有两种:

  1. 函数声明
1
2
3
function functionName(arg0, arg2, arg3) {
...code
}
  1. 函数表达式
1
2
3
var functionName = function(arg0, arg1, ard2) {
...code
}

这里只是简单介绍下,想了解很多请参考《JavaScript高级程序设计》

自执行函数(IIFE)

IIFE( 立即调用函数表达式)是一个在定义时就会立即执行的 JavaScript 函数。 –MDN

类似于下面的代码,就是一个自执行函数

1
2
3
(function(i, undefined){
console.log(i)
})(1, undefined)

第一眼看过去,怎么跟我们上面说的不一样啊,函数定义的方式不是只有函数声明和函数表达式吗?这是什么操作,写错了吧!别急,听我慢慢道来。
相信看过一些库的源码的小伙伴一定见过这种写法

1
2
3
~function(){
// 代码...
}();

或者这种方式

1
2
3
+function(){
// 代码...
}();

其实这些写法的作用都一样,都是把function()转化成一个可执行的表达式,方便执行。其实我们可以这样看

1
2
3
4
var fn = function(i, undefined){
console.log(i)
}
fn(i, undefined)

这样看是不是好理解多了,这不就是我们上面说的函数表达式定义函数嘛,只不过在这儿是让这个函数马上执行了而已。
但是如果我们这么写

这个时候,小伙伴们是不是心中就有个疑问了,为什么(function {// code})();可以被执行, 而function {// code}();却会报错?

  1. 首先我们要清楚,(function {// code})()是函数表达式,而function {// code}();是函数声明。
  2. js存在预编译的过程,在预编译的时候,会解释函数声明,而忽略函数表达式。
  3. 当js执行到function() {//code}();时, 由于function() {//code}在”预编译”阶段已经被解释过, js会跳过function(){//code}, 试图去执行();, 故会报错;
    当js执行到(function {// code})();时, 由于(function {// code})是表达式, js会去对它求解得到返回值, 由于返回值是一个函数, 故而遇到();时, 便会被执行。
    所以这个报错是在函数执行时才报错的,而不是在预编译阶段。

理解了第一个括号的意思,第二个括号的意思就简单多了,就是函数的执行表达式。

关于更多自执行函数的内容,可以参考Javascript模块化编程(一):模块的写法

匿名函数

顾名思义,匿名函数就是没有函数名的函数。
上面说到,JavaScript定义函数的两种方式利用函数声明和函数表达式,而匿名函数就是通过函数表达式创建的。

1
2
3
setTimeout(  
function(){ alert(1); } //这是一个匿名函数
, 2000);

上面的例子中函数并没有函数名,所以它就是一个匿名函数。

再来看看我们刚才的自执行函数

1
2
3
(function(i, undefined){
console.log(i)
})(1, undefined)

没错,这是一个自执行的匿名函数。
匿名函数的使用最主要就是方便,毕竟在很多情况下函数的名字并不那么重要。大多数情况下匿名函数和有名函数都可以很好地完成多数任务。

匿名函数还有一个最大的用途就是用来创建闭包,这个我们放在后面再说。


本文完