天天看點

javascript中的匿名函數

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

繼續閱讀