2012-07-24 56 views
4

我想寫「好」 javascript中的模塊化。理解JavaScript的模式

下面是一個模式,我發現,並正嘗試採用。不過,我對它的使用有些困惑。

說,例如,我有一個名爲「作業」頁面。該網頁上的所有JS功能將在類似封裝:

window.jobs = (function(jobs, $, undefined){ 
    return { 
     addNew: function(){ 
      // job-adding code 
     } 
    } 
})(window.jobs|| {}, jQuery); 

$(function(){ 
    $('.add_job').on('click', function(event){ 
     event.preventDefault(); 
     window.jobs.addNew(); 
    }); 
}); 

你大概可以扣除,所有我所做的就是更換所有會坐在匿名事件處理函數中的代碼,用調用我的全局作業對象中的函數。我不知道爲什麼這是一件好事,除了減少了可變碰撞的可能性,並使整個事情變得更加整潔,但對我來說這足夠好。

的 - 可能是相當明顯的 - 問題是:我所有的事件結合的init-類型的東西仍然坐在外面我閃亮的新工作對象:應該在哪裏呢?在作業對象內部?作業對象內的返回對象內部?在init()函數中?

我只是想了解一個穩定的基本框架,用於放入簡單的功能。我沒有構建JS應用程序,我只想編寫比它更健壯,更易維護的代碼目前。任何和所有的建議熱烈歡迎:)

+0

非常感謝您的非常有幫助的答案;我知道Crockfords和Osmanis以及Resigs有大量的信息,但這些概念與您自己的代碼有關的解釋會非常有幫助。我要將傑迪的迴應標記爲接受,因爲儘管我顯然無法說明哪一種方法是「正確」的解決方案,但他的回答似乎很好地解釋了我應該如何採用這種方法。 – Wintermute 2012-07-24 15:28:44

回答

2

可以打破在任何你喜歡的modules/objects人數太多應用程序。例如,您可以擁有另一個緩存和定義所有DOM節點的對象/模塊,以及另一個只處理任何事件的對象/模塊。因此,例如:

(function (win, doc, $, undef) { 
    win.myApp = win.myApp || { }; 

    var eventHandler = { 
     onJobClick: function(event) { 
      event.preventDefault(); 
      myApp.addNew(); 
     } 
    }; 

    var nodes = (function() { 
     var rootNode = $('.myRootNode'), 
      addJob = rootNode.find('.add_job'); 

     return { 
      rootNode: rootNode, 
      addJob: addJob 
     }; 
    }()); 

    $(function() { 
     myApp.nodes.addJob.on('click', myApp.handler.onJobClick); 
    }); 

    myApp.nodes = nodes; 
    myApp.handler = eventHandler; 
}(this, this.document, jQuery)); 

它並不真正的問題如何您在此創建(模塊)模式單身,無論是作爲文字,構造,Object.create()或諸如此類的東西。它需要符合你的要求。

但是,你應該嘗試創建儘可能多的特定模塊/對象作爲necesarry。當然,如果把這些單件/模塊/對象分成多個JavaScript文件並在需要時加載它們,並且在你說刀之前更有意義,那麼你就處於模塊化編程模式的世界,處理requireJS和AMD或CommonJS模塊。

+0

這個想法是保持模塊(JavaScript文件)範圍隔離。但是我們仍然需要模塊間的通信。通過CommonJS方式可以輕鬆實現 - 通過'exports'從模塊中導出任何您想要的內容,並通過'require'將其導入到模塊中。您可以將CommonJs模塊編譯爲適合瀏覽器的單個文件,其格式爲 https://github.com/dsheiko/cjsc或http://browserify.org。它甚至在ES6中以更明確的方式實現 - http://wiki.ecmascript.org/doku.php?id=harmony:modules 還有另一種方法。您可以定義注入每個模塊範圍的Mediator對象 – 2014-03-12 09:32:47

1

封裝明智,你很好:你甚至可以在jQuery封閉中聲明addNew,你仍然會避免全局範圍。我認爲你所得到的更多的是實現一些接近MVC架構的東西。

我喜歡的東西做的是創建使用DOM元素實例化一個對象,並把它自己綁定/提供方法來訪問它的控制等的護理

例子:

// (pretend we're inside a closure already) 
    var myObj = function(args){ 
     this.el = args.el; // just a selector, e.g. #myId 
     this.html = args.html; 
     this.bindings = args.bindings || {}; 
    } 

    myObj.prototype.appendTo = function(elem){ 
     elem.innerHTML += this.html; 
     this.bindControls(); 
    }; 

    myObj.prototype.remove = function(){ 
     $(this.el).remove(); // using jQuery 
    }; 

    myObj.prototype.bindControls = function(){ 
     for(var i in this.bindings){ // event#selector : function 
      var boundFunc = function(e){ return this.bindings[i].call(this,e); }; 
      $(this.el).on(i,boundFunc); 
     } 
    }; 
+0

這聽起來很像一個jQuery插件模式,這是否準確?無論如何,看到它像這樣崩潰是非常有用的。謝謝 - 在這裏,有一個upvote :) – Wintermute 2012-07-24 15:18:22

1

你現在正在做的方式正是我也是這樣做的,我通常在匿名函數本身內創建窗口對象,然後在其中聲明(在這種情況下:jClass = window.jClass)。

(function (jClass, $, undefined) { 

    /// <param name="$" type="jQuery" /> 

    var VERSION  = '1.31'; 
    UPDATED_DATE = '7/20/2012'; 

    // Private Namespace Variables 
    var _self   = jClass; // internal self-reference 
    jClass  = window.jClass; // (fix for intellisense) 
    $    = jQuery; // save rights to jQuery (also fixes vsdoc Intellisense) 

    // I init my namespace from inside itself 
    $(function() { 
     jClass.init('branchName'); 
    }); 

    jClass.init = function(branch) { 
     this._branch = branch; 
     this._globalFunctionality({ globalDatePicker: true }); 
     this._jQueryValidateAdditions(); 

     //put GLOBAL IMAGES to preload in the array 
     this._preloadImages(['']); 

     this._log('*******************************************************'); 
     this._log('jClass Loaded Successfully :: v' + VERSION + ' :: Last Updated: ' + UPDATED_DATE); 
     this._log('*******************************************************\n'); 
}; 

    jClass._log = function() { 
    //NOTE: Global Log (cross browser Console.log - for Testing purposes) 
    //ENDNOTE 

    try { console.log.apply(console, arguments); } 
    catch (e) { 
     try { opera.postError.apply(opera, arguments); } 
     catch (e) { /* IE Currently shut OFF : alert(Array.prototype.join.call(arguments, ' '));*/ } 
    } 
}; 

}(window.jClass= window.jClass|| {}, jQuery)); 

我之所以離開他們完全匿名的這個樣子,是讓我們在另一個文件中我想要更多的功能添加到這個JCLASS說。我簡單地創建另一個:

(function jClass, $, undefined) { 

jClass.newFunction = function (params) { 
    // new stuff here 
}; 

}(window.jClass = window.jClass || {}, jQuery)) 

正如你可以看到我喜歡object.object符號,但您可以使用對象文本對象:對象,它是由你!通過使所有這些獨立的,並封裝沒有實際的頁面邏輯

無論哪種方式更容易爲globalJS文件,並在每一頁上你的網站能夠使用它內有這樣的。如下面的例子。

jClass._log('log this text for me'); 

你不想糾結模型邏輯和業務邏輯,所以你在正確的道路分隔兩個,並允許您的全局命名空間/類/等上更靈活!

0

您可以在這裏找到關於模塊模式的綜合研究:http://www.adequatelygood.com/JavaScript-Module-Pattern-In-Depth.html它涵蓋了模塊範圍模塊方法的所有方面。然而,在實踐中你會有相當多的文件封裝你的代碼,所以問題是如何將它們的屬性結合起來。 AMD ...由每個模塊加載產生的多個HTTP請求將會嚴重損害您的頁面響應時間。因此,您可以將CommonJS編譯爲適合瀏覽器內使用的單個JavaScript文件。看看它是多麼容易http://dsheiko.github.io/cjsc/