(转)javascript中为何在匿名function函数后面还外加一个括号
详细研究过Javascript代码库(如Jquery、YUI)的人,一定会看到过很多如下形式的函数: (function(){...}())或 (function(){})()
它可以解释成为“匿名函数自调用”,也就是说,定义一个匿名函数,然后马上调用它(因为它是匿名的,如果不立即调用就获取不到该函数的引用了)。通常它被应用在一些大型的JS框架中(如上面所说的),因为这个匿名函数的函数体相当于提供一个匿名的名字空间,这样就不会再与用户自定义的JS函数、变量、对象发生冲突了。尽管JS没有显示地提供命名空间的定义和使用机制,但这种匿名方式却不失为是一种很好的解决命名空间问题的方法。
所以说,(function(){代码})()就等于执行了一个函数,只不过它是匿名的而已。如果在这个匿名函数内部想再次调用这个函数,就需要调用constructor属性了(这是Object中定义的,JS的继承机制如同Java一样保证了了所有对象都继承Object类)。
具体举个例子:
function test(){ return (function(p1,p2){ return p1+p2; })(1,2); } (function(){ alert(test()); })();//3
深入研究一下这种匿名函数:
function Foo() { var a = 123; this.a = 456; (function () { alert(a); // 123 alert(this.a); // undefined })(); }; var f=new Foo();
1 function Foo() { 2 var a = 123; 3 this.a = 456; 4 (function (_this) { 5 alert(a); // 123 6 alert(_this.a); // 456 7 })(this); 8 }; 9 var f = new Foo();
以上两个对比,说明:
(1)匿名函数可以直接访问到外层署名函数(Foo)中的变量(使用关键字var定义的),但不能访问外层署名函数的属性(使用关键字this定义的);
(2)匿名函数中的this指向的是匿名函数对象的地址,它与外层署名函数(Foo)对象的this指向的地址不同;
(3)匿名函数若要访问外层署名函数(Foo)中的属性,可以通过参数传递的方式实现。
1 function Foo() { 2 var a = 123; 3 this.a = 456; 4 (function (b) { 5 alert(a); // 123 6 alert(b); // 456 7 })(this.a); 8 }; 9 var f = new Foo();
1 (function () { 2 var a = 123; 3 this.a = 456; 4 (function () { 5 alert(a); // 123 6 alert(this.a); // 456 7 })(); 8 })();
以上两个对比,说明:
(1) 匿名函数既可以直接访问外层匿名函数中的变量,又直接可以访问外层匿名函数中的属性,而匿名函数却不可以直接访问外层已命名函数中的属性;
(2)以上两种方式可以实现相同的功能。
1 (function () { 2 var a = 123; 3 this.a = 456; 4 (function () { 5 alert(a); // 123 6 alert(this.a); // 456 7 this.b = 789; 8 })(); 9 (function () { 10 alert(this.b); // 789 11 })(); 12 })(); 13 (function () { 14 alert(this.a); // 456 15 alert(this.b); // 789 16 })();
1 function Foo() { 2 var a = 123; 3 this.a = 456; 4 (function () { 5 alert(a); // 123 6 alert(this.a); // undefined 7 this.b = 789; 8 })(); 9 (function () { 10 alert(this.b); // 789 11 })(); 12 }; 13 var f = new Foo(); 14 (function () { 15 alert(this.a); // undefined 16 alert(this.b); // 789 17 })();
以上两个对比,说明:
(1)匿名函数(即用两个小括号括起来的部分)位于一个执行上下文,不论这些代码放在哪个位置上。
1 function Foo() { 2 (function () { 3 this.b = 789; 4 })(); 5 (function () { 6 alert(this.b); // 789 7 alert(b); // 789 8 var a = 0; 9 alert(a); // 0 10 })(); 11 } 12 var f = new Foo(); 13 (function () { 14 alert(this.b); // 789 15 alert(b); // 789 16 })();
1 function Foo() { 2 (function () { 3 this.b = 789; 4 })(); 5 (function () { 6 alert(this.b); // 789 7 alert(b); // undefined 8 var b = 0; 9 alert(b); // 0 10 })(); 11 } 12 var f = new Foo(); 13 (function () { 14 alert(this.b); // 789 15 alert(b); // 789 16 })();
以上两个对比,说明:
(1)没有加 this取值时,如果当前 {} 中不存在同名的局部变量,则等同于加 this 处理;如果当前 {} 中存在同名的局部变量,则按常规处理。