看很多的网站的js文件,要面对的第一函数通常是匿名自执行函数,形如(function(){})(),它的作用有两个,一是匿名,在java中有匿名内部类,作用类似。匿名的意思是没有声名函数的名字,这样就使得函数外部无法访问匿名自执行函数的内部,防止函数之间变量命名的相互干扰,比如说有两个人写了两个js,放在同个网页中,如果它们没有用匿名函数包裹,这两个js文件之间的函数会互相调用,导致错误的产生。
那么如何访问匿名函数里面的函数呢?通常是在里面的函数或变量前加上window,这样该函数或变量就成为全局的了,在同个页面,即使是不同我js文件,也可以访问到,所以只要某个页面中加入jquery.js,那么其它js文件就可以用jquery(*)来访问jquery.js中的函数。
匿名自执行函数的另外一个作用是自执行,其实只要在js文件中写在任何代码,只要不包括function类型,它都会执行,它的作用有点像onload,不过onload是在页面载入完后才执行,它不用,所以如果它要调用某个页面元素,一定要将这个页面元素放在匿名自执行函数之前,否则会产生错误。
1. 什么是自执行的匿名函数?
它是指形如这样的函数: (function {// code})();
2. 疑问
为什么(function {// code})();可以被执行, 而function {// code}();却会报错?
3. 分析
(1). 首先, 要清楚两者的区别:
(function {// code})是表达式, function {// code}是函数声明.
(2). 其次, js"预编译"的特点:
js在"预编译"阶段, 会解释函数声明, 但却会忽略表式.
(3). 当js执行到function() {//code}();时, 由于function() {//code}在"预编译"阶段已经被解释过, js会跳过function(){//code}, 试图去执行();, 故会报错;
当js执行到(function {// code})();时, 由于(function {// code})是表达式, js会去对它求解得到返回值, 由于返回值是一 个函数, 故而遇到();时, 便会被执行.
在jquery中,匿名自执行函数中嵌套了匿名自执行函数,形如
代码如下 | 复制代码 |
(function(){ var a=function(){}; (function(){ a() })(); })(); |
这样写的目前是实现自调用,匿名自执行函数里的匿名自执行函数可以调用上级的函数。这也有点像java,类内的变量和方法对内部类是透明的。所以a=function中a之前不用加window,我们接着往下看
声明函数的一个方法:
代码如下 | 复制代码 |
var afun = function(){ alert(1); }; |
afun就是一个函数,准确的说是指向一个函数的变量或者指针,而如果没写afun,那么:
代码如下 | 复制代码 |
function(){ alert(1); }; |
就是一个匿名函数,因为没有名字,但是它还确实存在在内存中。没有名字的函数我们没有办法直接调用了,调用一个函数需要函数名加上一对小括号,比如afun()。那匿名函数能做什么呢?虽然没有名字,但是它可以把自己当成变量传给其它函数,比如:
代码如下 | 复制代码 |
var fun = function(afunction){ if(typeof afunction == "function"){ afunction(); } } fun(function(){ alert(1); }); |
虽然在定义这个函数时没有名字,但是它传递给fun之后,在fun的函数体内,它是有名字的,名字是afunction。这种用法其实很常见,再比如:
代码如下 | 复制代码 |
dojo.connect("adiv","onclick",function(){ alert("onclick"); }); |
匿名函数另一种用法就是自执行。函数名后面加上一对()就是执行这个函数,那么下面这个括号表达式就是定义一个函数,括号表达式的返回值就是这个函数:
代码如下 | 复制代码 |
(function(){ alert(1); }); |
在外面这对括号后再加上(),就是执行括号表达式返回的函数:
代码如下 | 复制代码 |
(function(){ alert(1); })(); |
这个就是匿名自执行函数,首先它没有名字,其次,它在定义之后会直接被执行,而且它没法再被执行,因为它没有名字。匿名自执行函数可以传参:
代码如下 | 复制代码 |
(function(i){ alert(i); })(1); |
匿名自执行函数有很多用处,主要是用于封装,比如看jquery或者dojo的源码发现它们都是封装在匿名自执行函数中,这样就可以做到页面加载时自动初始化,而且向外公开它想公开的属性和方法,而用到的临时变量可以安全封闭在匿名函数内。