2010-10-21 57 views
7

如果這個問題太寬泛,我很抱歉。實際上它有4個不同的問題,但都涉及到同一段代碼,我認爲它們都圍繞相同的原則。Javascript:這個代碼做什麼?

我今天決定,在使用JS多年後,實際上開始學習JS如何工作,而不是像在瀏覽器中運行的C那樣對待它。所以我開始深入研究jQuery代碼,以瞭解真正的JS開發人員如何使用該語言。那時候我發現了一段代碼,看起來像下面的代碼。請注意,我從另一個堆疊的帖子In Javascript, can you extend the DOM?處取下此代碼。所以這並不意味着寫這段代碼的人甚至知道他在說什麼。

var myDOM = (function(){ // #1 
    var myDOM = function(elems){ // #2 
      return new MyDOMConstruct(elems); 
     }, 
     MyDOMConstruct = function(elems) { 
      this.collection = elems[1] ? Array.prototype.slice.call(elems) : [elems]; 
      return this; // #3 
     }; 
    myDOM.fn = MyDOMConstruct.prototype = { 
     forEach : function(fn) { 
      var elems = this.collection; 
      for (var i = 0, l = elems.length; i < l; i++) { 
       fn(elems[i], i); 
      } 
      return this; 
     }, 
     addStyles : function(styles) { 
      var elems = this.collection; 
      for (var i = 0, l = elems.length; i < l; i++) { 
       for (var prop in styles) { 
        elems[i].style[prop] = styles[prop]; 
       } 
      } 
      return this; 
     } 
    }; 
    return myDOM; // #4 
})(); 

1爲什麼使用var myDOM =(function(){})();來聲明函數。而不是var myDOM = function(){};

2爲什麼要聲明另一個函數在myDOM函數中使用完全相同的名稱?爲什麼不將所有內部myDOM的邏輯放在外部myDOM函數中?

3爲什麼顯式返回「this」?那會自動完成,對嗎?

4這是怎麼回事?它是否返回內部myDOM的構造函數?如果是這樣,爲什麼?

更新

所以大部分的很有道理,現在。關於#1,我認爲myDOM被分配了=之後定義的函數,但事實並非如此。它被分配任何函數返回。這恰好是一個功能。

我還不清楚#3。是的,我明白使用這樣的功能

console.log(MyDomConstruct('foo')) 

會顯示'未定義'。但這不是它被使用的方式。一些排隊是這個

return new MyDomConstruct(elems); 

我能理解明確地返回「這個」如果語句是這樣進行的

return MyDomConstruct(elems); 

但事實並非如此。

+0

實際上'新的MyDomConstruct(elems)'不會返回'this',而是'MyDomConstruct'的新實例。也許在不同的情況下,這更容易理解。 – nre 2010-10-21 07:09:27

+0

對。但是「this」和MyDomConstruct的一個新實例都是MyDomConstruct的實例,不是嗎?此外,爲什麼即使使用「新」的語句,如果函數將返回自己的一個實例? – mellowsoon 2010-10-21 07:21:45

+0

所有不錯的答案。我給傑迪回答,因爲他先回答,但是對其他人回答+1。 – mellowsoon 2010-10-21 07:32:49

回答

9

爲什麼使用var myDOM =(function(){})();而不是var myDOM = function(){};

這就是所謂的self-invoking anonymous functionself-executing anonymous function。它的確如此,它在運行時調用它自己。你也會看到這樣的模式:

(function($){ 
}(jQuery)); 

在jQuery世界相當多。同樣的事情,在運行時,函數會自行調用並保證$符號對函數體內的jQuery對象有一個引用。

在您的代碼片段中,該函數調用它自己並返回myDOM,一個函數引用。

爲什麼要在myDOM函數中聲明另一個函數,並且名稱完全相同?爲什麼不將所有內部myDOM的邏輯放在外部myDOM函數中?

這只是一個約定。它可以被稱爲任何你想要的,也許作者認爲這樣做是方便的。這種模式的原因是安全隱私&。通過返回內部myDOM參考closure被創建。於是宣告像

var mytest = myDOM([]); 

後,你將不能訪問MyDOMConstruct,但你的內部函數做訪問。這樣你可以保護你的方法和變量。它也被稱爲method pattern。在這方面總是很好的閱讀Douglas Crockford: Javascript the good parts

爲什麼顯式返回「this」?那會自動完成,對嗎?

不,函數默認返回undefined的值。通過明確地返回this可以chain像的方法(從上面的例子呼叫):

mytest.forEach([]).addStyles([]); ... 

由於每個方法返回調用的對象,在這種情況下myDOM

這是怎麼回事?它是否返回內部myDOM的構造函數?如果是這樣,爲什麼?

我希望在這一點上應該清楚。

編輯

根據您的更新:

new MyDOMConstruct(); 

產生一個新的對象,inherits

MyDOMConstruct.prototype 

沒有new keywordthis不會被綁定到新的對象。相反,它將綁定到全局對象(窗口),並且您將使用this來訪問全局變量。

+0

謝謝jAndy。我更新了我的帖子,在#3上獲得了更多信息。 – mellowsoon 2010-10-21 07:02:17

+0

@mellowsoon:updated – jAndy 2010-10-21 07:28:23

6

1.爲什麼聲明使用的var myDOM = (function() {})();代替var myDOM = function() {};

使用的形式是一個自執行功能的功能。這意味着myDOM被設置爲函數返回的值。第二種形式將myDOM設置爲該函數,但不立即執行該功能。

var myDOM = (function() {   // <== This is a function that does something 
       // Something 
      })();     // The function is executed right HERE with(). 


2.爲什麼聲明完全相同的名稱MYDOM函數內其他功能?爲什麼不將所有內部myDOM的邏輯放在外部myDOM函數中?

因爲您正在返回內部myDOM函數在結束....所以命名實際上是有道理的事件,儘管它是在第一次混淆。這通常用於在JS中創建私有變量。由於內部函數將訪問它所包含的範圍(自我執行的匿名函數),但用戶不會。

var myDOM = (function() { // <== This is a function that is going to return 
          // a function/object 
       var myDOM = function() { // <== We're going to return this 
        ...     //  The outer myDom will be set to it 
       };      //  So it's actually helpful to name 
             //  it the same for clarity. 
       return myDOM; 
      })(); 

// Now we can access that inner object by using the outer myDOM. 
// We could access the inner object using myDOM even if the inner object 
// was named otherTHING... It's confusing to acces something 
// called otherTHING in the code by 
// writing myDOM().... so better name the inner returned function 
// myDOM as well. 

所以內部對象可以被命名爲任何東西,它可以與myDOM()執行,但如果你的名字的內部函數blah但你仍然可以通過使用myDOM()執行它......這不是很清楚..最好把它命名爲相同的。

3.爲什麼顯式返回「this」?那會自動完成,對嗎?

不,如果你沒有寫任何東西,Javascript會自動返回undefinedMDC reference:

返回this通常用於保留方法的上下文。它用於使方法鏈接($(here).is().a().chain().of().methods())成爲可能。因此,鏈下的方法知道它正在運行的上下文。

+0

感謝您的回答。關於#2,我想這就是爲什麼顯示一個jQuery對象 - 即console.log($(document)) - 顯示「jQuery()」而不是「jQuery.init()」,這是jQuery對象實際上是什麼據我所知)。這是因爲jQuery.init被分配給名爲jQuery的變量。奇怪的。 – mellowsoon 2010-10-21 07:04:58

3

只需再次注意自動執行匿名功能。在(function() { })();塊中包裝一些JavaScript代碼是創建私有名稱空間的一種方法。除了返回的值(在本例中爲myDOM)之外,您在內部函數內執行的所有操作都是功能私有的。

也就是說,你可以做save​​ly像

var counter = (function() { 
    var i = 0; 
    var counter = function() { 
     alert(i++); 
     return i; 
    } 
    return counter; 
})(); 

counter(); // will alert 0 
counter(); // will alert 1 
// ... and so on 

東西保留一些內部狀態,從祕密之外的功能。第二個原因,正如其他文章中所述,它不會污染變量爲i的全局命名空間。這就是爲什麼在jQuery插件開發中使用這些函數的最佳實踐。

+0

儘管我知道原則上自我執行的匿名函數是什麼,但出於某種原因,它始終沒有將我的想法用作一種方法或爲函數提供私有變量。他們不完全是私人財產,但它完成了同樣的事情。 – mellowsoon 2010-10-21 07:07:00

1

相同的,因爲這一個:


(function() { 
    function b(a) { 
     return new c(a) 
    } 
    function c(a) { 
     this.a = a[1] ? Array.prototype.slice.call(a) : [a]; 
     return this 
    } 
    b.b = c.prototype = {}; 
    return b 
})(); 

希望幫助... :)

1

例如: 變種FN =(函數(){ 恢復功能(){警報(11) }; })();當代碼運行時,現在的fn = function(){alert(11)}; 試試吧!