详细研究过Javascript代码库(如Jquery、YUI)的人,一定会看到过很多如下形式的函数:? (function(){...}()) 或 (function(){})()
???
????对于很多初学者来说,遇到它们经常会产生一系列问号:这是编程吗,用它做什么,怎么我没在其他语言里见过呢?
?
??? 接下来我就详细地解释一下:
?
??? 它可以解释成为“匿名函数自调用”,也就是说,定义一个匿名函数,然后马上调用它(因为它是匿名的,如果不立即调用就获取不到该函数的引用了)。通常它被应用在一些大型的JS框架中(如上面所说的),因为这个匿名函数的函数体相当于提供一个匿名的名字空间,这样就不会再与用户自定义的JS函数、变量、对象发生冲突了。尽管JS没有显示地提供命名空间的定义和使用机制,但这种匿名方式却不失为是一种很好的解决命名空间问题的方法。
?
??? 所以说,(function(){代码})()就等于执行了一个函数,只不过它是匿名的而已。如果在这个匿名函数内部想再次调用这个函数,就需要调用constructor属性了(这是Object中定义的,JS的继承机制如同Java一样保证了了所有对象都继承Object类)。
?
????明白了它是什么了,下面我们就要学习该怎样使用它了,以下这些问题是我们会经常遇到的,不如提前做好理论只是准备以备后期能顺利地实现开发。请看下面问题:
???
1、下列哪些正确?(B、C)
A.function(){
?????? alert("Here!");
??? }();
B.(function(){
?????? alert("Here!");
??? })();
C.(function(){
?????? alert("Here!");
??? }());
2、下列哪个结果是正确的?(A、B、C、D)
A.(function(a1,a2){
?????? alert("Here!"+(a1+a2));
??? })(1,2);
B.(function(a1,a2){
?????? alert("Here!" +(a1+a2));
??? }(1,2));
C.void function(a1,a2){
?????? alert("Here!" +(a1+a2));
??? }(1,2);
D.var f = function(a1,a2){
?????? alert("Here!" +(a1+a2));
??? }(1,2);?
?? 注:A 、B、C与D四种格式都正确,前两者属于同种情况的不同写法,后两种是将函数对象的返回值赋给其他变量,C是忽略函数返回值,而D正相反!
?????
????? 具体举个例子:
function test(){
????????? return (function(p1,p2){
???????????????????????? ?? return p1+p2;
????????? })(1,2);
};
(function(){
????????? alert(test());
}());
??
?
?????
????? 下面我们就深入研究一下这种匿名函数:
1、
①
function Foo() {?
??? var a = 123;?
??? this.a = 456;?
??? (function() {
?????? alert(a); // 123
?????? alert(this.a); // undefined?
??? })();?
};
var f = new Foo();
?
②?
function Foo() {?
??? var a = 123;?
??? this.a = 456;?
??? (function(_this) {
?????? alert(a); // 123
?????? alert(_this.a); // 456?
??? })(this);?
};
var f = new Foo();
?
以上两个对比,说明:
(1)匿名函数可以直接访问到外层署名函数(Foo)中的变量(使用关键字var定义的),但不能访问外层署名函数的属性(使用关键字this定义的);
(2)匿名函数中的this指向的是匿名函数对象的地址,它与外层署名函数(Foo)对象的this指向的地址不同;
(3)匿名函数若要访问外层署名函数(Foo)中的属性,可以通过参数传递的方式实现。?
?
2、
①?
function Foo() {?
??? var a = 123;?
??? this.a = 456;?
??? (function(b) {
?????? alert(a); // 123
?????? alert(b); // 456?
??? })(this.a);?
};
var f = new Foo();
?
②
(function() {?
??? var a = 123;?
??? this.a = 456;?
??? (function() {
?????? alert(a); // 123
?????? alert(this.a); // 456?
??? })();
})();
以上两个对比,说明:
(1) 匿名函数既可以直接访问外层匿名函数中的变量,又直接可以访问外层匿名函数中的属性,而匿名函数却不可以直接访问外层已命名函数中的属性;
(2)以上两种方式可以实现相同的功能。
?
3、
①
(function() {?
??? var a = 123;?
??? this.a = 456;?
??? (function() {?
?????? alert(a); // 123?
?????? alert(this.a); // 456?
?????? this.b = 789;?
??? })();?
??? (function() {?
?????? alert(this.b); // 789?
??? })();?
})();
(function() {
??? alert(this.a); // 456
??? alert(this.b); // 789?
})();
?
②
function Foo() {?
??? var a = 123;?
??? this.a = 456;
??? (function() {?
?????? alert(a); // 123?
?????? alert(this.a); // undefined?
?????? this.b = 789;?
??? })();?
??? (function() {?
?????? alert(this.b); // 789?
??? })();?
};
var f = new Foo();?
(function() {
??? alert(this.a); // undefined
??? alert(this.b); // 789?
})();
??
以上两个对比,说明:
(1)匿名函数(即用两个小括号括起来的部分)位于一个执行上下文,不论这些代码放在哪个位置上。
?
4、
①
function Foo() {
(function() {
this.b = 789;
})();
(function() {
alert(this.b); // 789
alert(b); // 789
var a = 0;
alert(a); // 0
})();
}
var f = new Foo();
(function() {
alert(this.b); // 789
alert(b); // 789
})();
?
②
function Foo() {
(function() {
this.b = 789;
})();
(function() {
alert(this.b); // 789
alert(b); // undefined
var b = 0;
alert(b); // 0
})();
}
var f = new Foo();
(function() {
alert(this.b); // 789
alert(b); // 789
})();
?
以上两个对比,说明:
(1)没有加 this取值时,如果当前 {} 中不存在同名的局部变量,则等同于加 this 处理;如果当前 {} 中存在同名的局部变量,则按常规处理。
?
?
??????以上只是鄙人的粗浅见解,内容还不够完整,还会不断完善删改,如其中有什么错误之处还望读者谅解,真诚希望能留下您的宝贵建议,以图修改!这里欢迎每一位爱好JS的读者,真心希望能和你们交流心得!
alert("Here!");
}());
这种写法以前倒还不知道,
jquery里面是这种写法哦:
(function(x,y){
...
})(window,undefined);
<head></head>
<title>js test</title>
<body>
<script language="javascript">
//看了这段代码突然好奇这两个匿名函数中的this指的是哪个对象?为此测试了一下:
(function() {
var a = 123;
this.a = 456;
(function() {
alert("#1 "+a); // 123
alert("#1"+this.a); // 456
this.b = 789;
})();
(function() {
alert("#2"+this.b); // 789
})();
})();
(function() {
alert("#3"+this.a); // 456
alert("#3"+this.b); // 789
for(var prop in this){ //罗列出this的所有可迭代的属性及其值,有window对象特有的一些属性,判断this可能就是window对象
alert(prop+": "+this[prop]);
}
alert(this == window); // true,证明这个匿名函数中的this就是指向window对象
alert("window.a "+window.a+" window.b "+window.b); //这边可以取到a,b的值,进一步证明了这两个匿名函数中的this就是window对象
alert("#3 a "+a); //456,通过var声明的a被this.a覆盖掉了
})();
alter("window.a"+window.a+" window.b"+window.b); //js error。但是奇怪的是在匿名函数以外,window对象并不存在属性a,b
//现实是: 自执行的匿名函数中通过this关键字修改到外部执行环境(对象)的属性后,在另外的匿名函数中可以访问到这些属性,但在匿名函数以外,这些属性确无法访问。
//问题是: 我还无法解释这种现象。想听听博主的高见。
</script>
</body>
</html>
很不好意思,由于很忙,没来得及看博客,还望原谅!我认真看了你的问题,仔细考虑和测试后,现在把答案告诉你,前提这只是我的个人意见,如有错误还请指出。言归正传:
首先,提示你最后的函数名称写错了(alert,不是alter),改正过了就通过了;
其次,你上面说“通过var声明的a被this.a覆盖掉了”这句话是不对的,它没有被覆盖,只是访问不到它的应用域,而此处省略掉this的a为什么访问的是匿名函数的属性呢?
为此,我专门写了一篇文章《谈JS中匿名函数的上下文环境》,希望它能够为你解答,O(∩_∩)O~
楼主的回答确实没错,我都在Chrome中测试了。
<head></head>
<title>js test</title>
<body>
<script language="javascript">
//看了这段代码突然好奇这两个匿名函数中的this指的是哪个对象?为此测试了一下:
(function() {
var a = 123;
this.a = 456;
(function() {
alert("#1 "+a); // 123
alert("#1"+this.a); // 456
this.b = 789;
})();
(function() {
alert("#2"+this.b); // 789
})();
})();
(function() {
alert("#3"+this.a); // 456
alert("#3"+this.b); // 789
for(var prop in this){ //罗列出this的所有可迭代的属性及其值,有window对象特有的一些属性,判断this可能就是window对象
alert(prop+": "+this[prop]);
}
alert(this == window); // true,证明这个匿名函数中的this就是指向window对象
alert("window.a "+window.a+" window.b "+window.b); //这边可以取到a,b的值,进一步证明了这两个匿名函数中的this就是window对象
alert("#3 a "+a); //456,通过var声明的a被this.a覆盖掉了
})();
alter("window.a"+window.a+" window.b"+window.b); //js error。但是奇怪的是在匿名函数以外,window对象并不存在属性a,b
//现实是: 自执行的匿名函数中通过this关键字修改到外部执行环境(对象)的属性后,在另外的匿名函数中可以访问到这些属性,但在匿名函数以外,这些属性确无法访问。
//问题是: 我还无法解释这种现象。想听听博主的高见。
</script>
</body>
</html>