javascript中為何在匿名function函數后面還外加一個括號
詳細研究過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的讀者,真心希望能和你們交流心得!