javascript - jquery' title




在JavaScript代碼組織中常用的最佳實踐 (19)

隨著jQuery等JavaScript框架使客戶端Web應用程序更加豐富和功能更強大,我開始注意到一個問題......

你如何保持這種有組織的?

  • 把所有的處理程序放在一個地方,並為所有事件編寫函數?
  • 創建函數/類來包裝所有的功能?
  • 寫得像瘋了一樣,只是希望它能夠最好地工作?
  • 放棄並獲得新的職業?

我提到了jQuery,但它通常是任何JavaScript代碼。 我發現隨著線條開始堆積起來,管理腳本文件或找到您要查找的內容變得更加困難。 我發現最大的可能性是有很多方法可以做同樣的事情,很難知道哪一個是目前普遍接受的最佳實踐。

有沒有關於如何讓你的.js文件像應用程序的其他部分一樣漂亮整潔的最佳方法的一般建議? 或者這只是IDE的問題? 那裡有更好的選擇嗎?

編輯

這個問題旨在更多地關注代碼組織,而不是文件組織。 有一些非常好的合併文件或分割內容的例子。

我的問題是:目前普遍接受的最佳實踐方法是如何組織實際的代碼? 你用什麼方式,甚至是推薦的方式來與頁面元素進行交互,並創建不會相互衝突的可重用代碼?

有些人列出了名字空間 ,這是一個好主意。 還有其他什麼方式,更具體地處理頁面上的元素並保持代碼的組織和整齊?


“寫得像瘋了一樣,只是希望它能最好地工作?”,我見過這樣的項目,這個項目是由2個開發人員開發和維護的,這是一個包含大量JavaScript代碼的龐大應用程序。 除此之外,你可以想到的每個可能的jquery函數都有不同的快捷鍵。 我建議他們將代碼組織為插件,因為這是類,模塊,命名空間和整個宇宙的jQuery等價物。 但事情變得更糟,現在他們開始編寫插件,替換項目中使用的3行代碼的每個組合。 個人認為我認為jQuery是魔鬼,它不應該用於有很多JavaScript的項目,因為它鼓勵你懶惰,不想以任何方式組織代碼。 我寧願閱讀100行的JavaScript,而不是40行鏈接的jQuery函數(我不是在開玩笑)。 與流行的觀點相反,很容易將JavaScript代碼組織為名稱空間和類的等價物。 這就是YUI和Dojo所做的。 如果你喜歡,你可以輕鬆推出自己的產品。 我發現YUI的方法更好更高效。 但是如果你想寫任何有用的東西,你通常需要一個好的編輯器來支持片段來彌補YUI命名約定。


Dojo在第一天就擁有了模塊系統。 事實上,它被認為是Dojo的基石,它將所有這些東西結合在一起:

使用模塊Dojo實現以下目標:

  • Dojo代碼和自定義代碼的命名空間( dojo.declare() ) - 不會污染全局空間,與其他庫共存,以及用戶的非Dojo感知代碼。
  • 按名稱同步或異步加載模塊( dojo.require() )。
  • 通過分析模塊依賴性來自定義構建,以創建單個文件或一組相互依賴的文件(所謂的圖層),以僅包含您的Web應用程序所需的內容。 定製版本可以包含Dojo模塊和客戶提供的模塊。
  • 透明的基於CDN的Dojo訪問和用戶代碼。 美國在線和谷歌都以這種方式運營Dojo,但一些客戶也為他們的自定義網絡應用程序提供這種服務。


I use a custom script inspired by Ben Nolan's behaviour (I can't find a current link to this anymore, sadly) to store most of my event handlers. These event handlers are triggered by the elements className or Id, for example. 例:

Behaviour.register({ 
    'a.delete-post': function(element) {
        element.observe('click', function(event) { ... });
    },

    'a.anotherlink': function(element) {
        element.observe('click', function(event) { ... });
    }

});

I like to include most of my Javascript libraries on the fly, except the ones that contain global behaviour. I use Zend Framework's headScript() placeholder helper for this, but you can also use javascript to load other scripts on the fly with Ajile for example.


You can use jquery mx (used in javascriptMVC) which is a set of scripts that allows you to use models, views, and controllers. I've used it in a project and helped me create structured javascript, with minimal script sizes because of compression. This is a controller example:

$.Controller.extend('Todos',{
  ".todo mouseover" : function( el, ev ) {
   el.css("backgroundColor","red")
  },
  ".todo mouseout" : function( el, ev ) {
   el.css("backgroundColor","")
  },
  ".create click" : function() {
   this.find("ol").append("<li class='todo'>New Todo</li>"); 
  }
})

new Todos($('#todos'));

You can also use only the controller side of jquerymx if you aren't interested in the view and model parts.


You don't mention what your server-side language is. Or, more pertinently, what framework you are using -- if any -- on the server-side.

IME, I organise things on the server-side and let it all shake out onto the web page. The framework is given the task of organising not only JS that every page has to load, but also JS fragments that work with generated markup. Such fragments you don't usually want emitted more than once - which is why they are abstracted into the framework for that code to look after that problem. :-)

對於必鬚髮布自己的JS的最終頁面,我通常會發現生成的標記中存在邏輯結構。這種本地化的JS通常可以在這樣的結構的開始和/或結束時進行組裝。

請注意,這不會讓您無法編寫高效的JavaScript! :-)


以Jquery為中心的NameSpace方式組織代碼可能如下所示......並且不會與其他JavaScript API(如Prototype,Ext)發生衝突。

<script src="jquery/1.3.2/jquery.js" type="text/javascript"></script>
<script type="text/javascript">

var AcmeJQ = jQuery.noConflict(true);
var Acme = {fn: function(){}};

(function($){

    Acme.sayHi = function()
    {
        console.log('Hello');
    };

    Acme.sayBye = function()
    {
        console.log('Good Bye');
    };
})(AcmeJQ);

// Usage
//          Acme.sayHi();
// or
// <a href="#" onclick="Acme.sayHi();">Say Hello</a>


</script>

希望這可以幫助。


創建假類,並確保任何可以拋入單獨函數的東西都是合理的。 此外,請確保評論很多,而不是寫sparsehetti代碼,而是將所有代碼都保存在一個分區中。 例如,一些無意義的代碼描繪了我的理想。 很顯然,在現實生活中,我還編寫了許多基本上涵蓋其功能的庫。

$(function(){
    //Preload header images
    $('a.rollover').preload();

    //Create new datagrid
    var dGrid = datagrid.init({width: 5, url: 'datalist.txt', style: 'aero'});
});

var datagrid = {
    init: function(w, url, style){
        //Rendering code goes here for style / width
        //code etc

        //Fetch data in
        $.get(url, {}, function(data){
            data = data.split('\n');
            for(var i=0; i < data.length; i++){
                //fetching data
            }
        })
    },
    refresh: function(deep){
        //more functions etc.
    }
};

在我上一個項目-Viajeros.com中,我使用了幾種技術的組合。 我不知道如何組織一個網絡應用程序 - Viajeros是一個具有明確定義的部分的旅客的社交網站,所以它很容易分離每個區域的代碼。

根據站點部分,我使用命名空間模擬和模塊延遲加載。 在每一頁加載時,我聲明一個“vjr”對象,並且總是為它加載一組常用函數(vjr.base.js)。 然後每個HTML頁面通過一個簡單的方式決定哪些模塊需要:

vjr.Required = ["vjr.gallery", "vjr.comments", "vjr.favorites"];

Vjr.base.js從服務器獲取每一個gzip並執行它們。

vjr.include(vjr.Required);
vjr.include = function(moduleList) {
  if (!moduleList) return false;
  for (var i = 0; i < moduleList.length; i++) {
    if (moduleList[i]) {
      $.ajax({
        type: "GET", url: vjr.module2fileName(moduleList[i]), dataType: "script"
      });
    }
  }
};

每個“模塊”都有這樣的結構:

vjr.comments = {}

vjr.comments.submitComment = function() { // do stuff }
vjr.comments.validateComment = function() { // do stuff }

// Handlers
vjr.comments.setUpUI = function() {
    // Assign handlers to screen elements
}

vjr.comments.init = function () {
  // initialize stuff
    vjr.comments.setUpUI();
}

$(document).ready(vjr.comments.init);

鑑於我有限的Javascript知識,我知道必須有更好的方法來管理這一點,但直到現在它對我們來說都非常有用。


在我之前的工作中,我能夠成功地將Javascript模塊模式應用到Ext JS應用程序。 它提供了一個簡單的方法來創建很好的封裝代碼。


守則組織要求採用公約和文件標準:
1.物理文件的命名空間代碼;

Exc = {};


2.在這些命名空間中分組javascript;
3.設置用於表示真實世界對象的原型或相關函數或類;

Exc = {};
Exc.ui = {};
Exc.ui.maskedInput = function (mask) {
    this.mask = mask;
    ...
};
Exc.ui.domTips = function (dom, tips) {
    this.dom = gift;
    this.tips = tips;
    ...
};


4.設置約定來改進代碼。 例如,將其所有內部函數或方法分組到其對像類型的類屬性中。

Exc.ui.domTips = function (dom, tips) {
    this.dom = gift;
    this.tips = tips;
    this.internal = {
        widthEstimates: function (tips) {
            ...
        }
        formatTips: function () {
            ...
        }
    };
    ...
};


5.製作名稱空間,類,方法和變量的文檔。 必要時還要討論一些代碼(一些FI和Fors,他們通常實現代碼的重要邏輯)。

/**
  * Namespace <i> Example </i> created to group other namespaces of the "Example".  
  */
Exc = {};
/**
  * Namespace <i> ui </i> created with the aim of grouping namespaces user interface.
  */
Exc.ui = {};

/**
  * Class <i> maskdInput </i> used to add an input HTML formatting capabilities and validation of data and information.
  * @ Param {String} mask - mask validation of input data.
  */
Exc.ui.maskedInput = function (mask) {
    this.mask = mask;
    ...
};

/**
  * Class <i> domTips </i> used to add an HTML element the ability to present tips and information about its function or rule input etc..
  * @ Param {String} id - id of the HTML element.
  * @ Param {String} tips - tips on the element that will appear when the mouse is over the element whose identifier is id <i> </i>.
  */
  Exc.ui.domTips = function (id, tips) {
    this.domID = id;
    this.tips = tips;
    ...
};


這些只是一些提示,但對組織代碼有很大的幫助。 記住你必須有紀律才能成功!


對於JavaScript組織一直在使用以下內容

  1. 所有的JavaScript文件夾
  2. 頁面級別的javascript獲取其自己的文件與頁面的相同名稱。 ProductDetail.aspx將是ProductDetail.js
  3. 在庫文件的JavaScript文件夾內,我有一個lib文件夾
  4. 將相關的庫函數放在一個你想在整個應用程序中使用的lib文件夾中。
  5. Ajax是我在javascript文件夾之外移動的唯一javascript,並且獲取它自己的文件夾。 然後我添加兩個子文件夾客戶端和服務器
  6. 客戶端文件夾獲取所有.js文件,而服務器文件夾獲取所有服務器端文件。

您可以將腳本分成單獨的文件進行開發,然後創建一個“發布”版本,將所有腳本塞到一起並運行YUI Compressor或類似的東西。


我使用Dojo的包管理dojo.requiredojo.provide )和類系統( dojo.declare ,它也允許簡單的多重繼承)將我所有的類/小部件模塊化為單獨的文件。 不僅可以使代碼保持組織,還可以讓你在類/小部件中進行懶/加載。


我為每件事情創建了單例,我不需要在屏幕上多次實例化,也可以為其他任何類實例化。 它們都放在同一個文件中的同一個命名空間中。 所有內容都經過評論,並使用UML和狀態圖進行設計。 javascript代碼清除了html,所以沒有內聯javascript,我傾向於使用jquery來最小化跨瀏覽器問題。


我的老闆仍然談到他們編寫模塊化代碼(C語言)的時代,並抱怨現在代碼有多糟糕! 據說程序員可以在任何框架中編寫程序集。 總是有一個戰略來克服代碼組織。 基本的問題在於那些把java腳本當作玩具並且從不嘗試去學習的人。

就我而言,我使用正確的init_screen()在UI主題或應用程序屏幕的基礎上編寫js文件。 使用適當的id命名約定,我確保在根元素級別沒有名稱空間衝突。 在unobstrusive window.load()中,我根據頂層id綁定這些東西。

我嚴格使用java腳本關閉和模式來隱藏所有私有方法。 做完這些之後,永遠不會遇到屬性/函數定義/變量定義衝突的問題。 但是,與團隊合作時,執行同樣的嚴格程序通常很困難。


我認為這可能與DDD(領域驅動設計)有關。 我正在處理的應用程序雖然缺乏正式的API,但通過服務器端代碼(類/文件名等)提供了這樣的提示。 有了這個,我創建了一個頂級對像作為整個問題域的容器; 然後,我在需要的地方添加了命名空間:

var App;
(function()
{
    App = new Domain( 'test' );

    function Domain( id )
    {
        this.id = id;
        this.echo = function echo( s )
        {
            alert( s );
        }
        return this;
    }
})();

// separate file
(function(Domain)
{
    Domain.Console = new Console();

    function Console()
    {
        this.Log = function Log( s )
        {
            console.log( s );
        }
        return this;
    }
})(App);

// implementation
App.Console.Log('foo');

查看JavasciptMVC

您可以 :

  • 將你的代碼分解成模型,視圖和控制器層。

  • 將所有代碼壓縮到單個生產文件中

  • 自動生成代碼

  • 創建和運行單元測試

  • 還有更多...

最重要的是,它使用jQuery,所以你也可以利用其他jQuery插件。






formatting