詳細研究過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 處理;如果目前 {} 中存在同名的局部變量,則按正常處理