jQuery學習--Code Organization Concepts

來源:互聯網
上載者:User

標籤:--   訊息   moved   介紹   大型   mon   cli   應該   example   

jQuery官方文檔:  http://learn.jquery.com/code-organization/concepts/

 

Code Organization Concepts(程式碼群組織概念)

當你不再只是用jQuery為你的網站增添一些簡單的功能,轉向做一些成熟的用戶端應用,那你就需要考慮如何組織你的代碼。這章,我們將簡要地介紹jQuery應用中幾種常用的程式碼群組織模式,探究RequireJS依賴管理以及構建系統。

When you move beyond adding simple enhancements to your website with jQuery and start developing full-blown(成熟的) client-side applications, you need to consider how to organize your code. In this chapter, we‘ll take a look at various code organization patterns you can use in your jQuery application and explore the RequireJS dependency management and build system.

Key Concepts(關鍵概念)

在開始學習程式碼群組織模式之前,理解一些通用的優良的程式碼群組織模式是非常重要的。

Before we jump into code organization patterns, it‘s important to understand some concepts that are common to all good code organization patterns.

代碼應該按照功能為單位劃分,例如:模組、服務等等。不要把所有的代碼都堆在一個大大的$( document ).ready()的塊中。這種觀點,不嚴謹地說,可以叫做“封裝”。

  • Your code should be divided into units of functionality — modules, services, etc. Avoid the temptation to have all of your code in one huge $( document ).ready() block. This concept, loosely, is known as encapsulation.

不要重複copy代碼,找出函數中相似功能的程式碼片段,利用繼承技術避免重複代碼。

  • Don‘t repeat yourself. Identify similarities among pieces of functionality, and use inheritance techniques to avoid repetitive code.

儘管jQuery原本就是以DOM操作為中心的,但是JavaScript應用不限於DOM。請記住不是所有的函數都需要或者都應該有一個DOM呈現。

  • Despite jQuery‘s DOM-centric nature, JavaScript applications are not all about the DOM. Remember that not all pieces of functionality need to — or should — have a DOM representation.

函數單元之間應該是松耦合的,即一個函數單元的執行應該只依賴於它本身,函數單元之間的通訊應該通過類似使用者事件或發布/訂閱的訊息系統處理。儘可能避免函數單元之間直接通訊。松耦合概念對於首次嘗試開發複雜應用的開發人員來說,尤其難以拿捏,所以在開始開發後需要特別留心松偶爾原則。

  • Units of functionality should be loosely coupled, that is, a unit of functionality should be able to exist on its own, and communication between units should be handled via a messaging system such as custom events or pub/sub. Stay away from direct communication between units of functionality whenever possible.

The concept of loose coupling can be especially troublesome to developers making their first foray into complex applications, so be mindful of this as you‘re getting started.

Encapsulation 封裝

組織代碼第一步就是,把應用的程式碼片段拆分成很多不同塊,有時,僅僅這樣做就夠了。

The first step to code organization is separating pieces of your application into distinct pieces; sometimes, even just this effort is sufficient to lend

The Object Literal  對象字面量

對象字面量也許是封裝相關代碼最簡單的方法。雖然它沒有提供任何屬性或方法的存取權限控制,但是對於消除匿名函數、以配置項為中心、代碼複用和重構是非常有用的。

An object literal is perhaps the simplest way to encapsulate related code. It doesn‘t offer any privacy for properties or methods, but it‘s useful for eliminating anonymous functions from your code, centralizing configuration options, and easing the path to reuse and refactoring.

 1 var myFeature = { 2    myProperty:"Hello", 3     4    myMethod:function(){ 5         console.log(myFeature.myProperty);     //console.log(this.myProperty)  一樣? 6     }, 7     init:function(settings){ 8     myFeature.settings = settings;  9    },10    myReadSetting:function(){11     console.log(myFeature.settings);12 }13   14 };    15 16 myFeature.myProperty === "Hello";//true17 myFeature.myMethod();   // myFeature.myMethod是函數,加了小括弧才是調用該函數18 myFeature.init({foo:"bar"});19 myFeature.myReadSetting();

 所有屬性和方法都是public的,所以屬性和方法可以在應用任意位置調用。有一個init方法,然而無需其他,在對象   之前就可以調用它。

The object literal above is simply an object assigned to a variable. The object has one property and several methods. All of the properties and methods are public, so any part of your application can see the properties and call methods on the object. While there is an init method, there‘s nothing requiring that it be called before the object is functional.

在jQuery代碼中如何運用這種模式呢?比方說我們用傳統的jQuery風格寫了如下代碼:

How would we apply this pattern to jQuery code? Let‘s say that we had this code written in the traditional jQuery style:

//點擊列表中某項,通過該項的id載入一些內容,並隱藏兄弟項的內容。
// Clicking on a list item loads some content using the// list item‘s ID, and hides content in sibling list items$( document ).ready(function() { $( "#myFeature li" ).append( "<div>" ).click(function() { var item = $( this ); var div = item.find( "div" ); div.load( "foo.php?item=" + item.attr( "id" ), function() { div.show(); item.siblings().find( "div" ).hide(); }); });});

如果這隻是我們應用中的代碼,這樣做是可以的。然而,如果它是一個大型應用中的一段代碼,我們最好拆分不相干的功能。我們也許會把URL挪到代碼外部做成設定檔,最後,為了後續更加容易修改功能塊,我們將拆解jQuery調用鏈。

If this were the extent of our application, leaving it as-is would be fine. On the other hand, if this was a piece of a larger application, we‘d do well to keep this functionality separate from unrelated functionality. We might also want to move the URL out of the code and into a configuration area. Finally, we might want to break up the chain to make it easier to modify pieces of the functionality later.

// Using an object literal for a jQuery featurevar myFeature = {    init: function( settings ) {        myFeature.config = {            items: $( "#myFeature li" ),            container: $( "<div class=‘container‘></div>" ),            urlBase: "/foo.php?item="        };         // Allow overriding the default config        $.extend( myFeature.config, settings );         myFeature.setup();    },     setup: function() {        myFeature.config.items            .each( myFeature.createContainer )            .click( myFeature.showItem );    },     createContainer: function() {        var item = $( this );        var container = myFeature.config.container            .clone()            .appendTo( item );        item.data( "container", container );    },     buildUrl: function() {        return myFeature.config.urlBase + myFeature.currentItem.attr( "id" );    },     showItem: function() {        myFeature.currentItem = $( this );        myFeature.getContent( myFeature.showContent );    },     getContent: function( callback ) {        var url = myFeature.buildUrl();        myFeature.currentItem.data( "container" ).load( url, callback );    },     showContent: function() {        myFeature.currentItem.data( "container" ).show();        myFeature.hideContent();    },     hideContent: function() {        myFeature.currentItem.siblings().each(function() {            $( this ).data( "container" ).hide();        });    }}; $( document ).ready( myFeature.init );

你最先注意到的是這個方法比原來的大多了,其次,如果在我們自己應用中使用這些代碼,對象直接量看上去有點過分複雜。假設它不是我們應用中的實現,我們會獲得以下幾點:

The first thing you‘ll notice is that this approach is obviously far longer than the original — again, if this were the extent of our application, using an object literal would likely be overkill. Assuming it‘s not the extent of our application, though, we‘ve gained several things:

我們把feature分解成小的方法,將來如果我們想要修改content如何顯示,我們可以很清晰地知道在哪裡修改它。在原先的代碼中,難於找到修改位置。

  • We‘ve broken our feature up into tiny methods. In the future, if we want to change how content is shown, it‘s clear where to change it. In the original code, this step is much harder to locate.

我們消除了匿名方法的使用

  • We‘ve eliminated the use of anonymous functions.

我們將配置項移到代碼體外,把他們放到了中心的位置。

  • We‘ve moved configuration options out of the body of the code and put them in a central location.

我們消除了鏈式調用的約束,使得代碼更容易重構、混合、重新組織。

  • We‘ve eliminated the constraints of the chain, making the code easier to refactor, remix, and rearrange.

 

比較重要的特性,對象直接量相對把一段很長的代碼寫在$(document).ready()塊中,是一個明顯的提升,因為它讓我們得以思考我們的各個功能塊。然而,比起簡單地把一堆函式宣告在一個$(document).ready()塊中也沒有好太多。

For non-trivial features, object literals are a clear improvement over a long stretch of code stuffed in a $( document ).ready()block, as they get us thinking about the pieces of our functionality. However, they aren‘t a whole lot more advanced than simply having a bunch of function declarations inside of that $( document ).ready() block.

The Module Pattern(模組化)

模組化克服了對象字面量的限制,提供了變數和函數的私用許可權控制。

The module pattern overcomes some of the limitations of the object literal, offering privacy for variables and functions while exposing a public API if desired.

// The module patternvar feature = (function() {     // Private variables and functions    var privateThing = "secret";    var publicThing = "not secret";     var changePrivateThing = function() {        privateThing = "super secret";    };     var sayPrivateThing = function() {        console.log( privateThing );        changePrivateThing();    };     // Public API    return {        publicThing: publicThing,        sayPrivateThing: sayPrivateThing    };})(); feature.publicThing; // "not secret" // Logs "secret" and changes the value of privateThingfeature.sayPrivateThing();

在上面的例子中,我們立即執行一個匿名函數並返回一個對象,在函數中,我們定義了一些變數。因為變數定義在函數中,我們從外部沒有許可權訪問函數內部的變數,除非我們把他們放在return的對象中。這意味著,函數外部代碼無法訪問privateThing變數和changePrivateThing函數。然而sayPrivateThing有許可權訪問privateThing和changePrivateThing,因為它們都定義在和sayPrivateThing相同的範圍中。

In the example above, we self-execute an anonymous function that returns an object. Inside of the function, we define some variables. Because the variables are defined inside of the function, we don‘t have access to them outside of the function unless we put them in the return object. This means that no code outside of the function has access to the privateThing variable or to the changePrivateThing function. However, sayPrivateThing does have access to privateThing and changePrivateThing, because both were defined in the same scope as sayPrivateThing.

這種模式是非常強大的,因為你能從變數名中推測,它可以提供你私人變數和函數,當訪問受限的API介面,返回的對象的屬性和方法。

This pattern is powerful because, as you can gather from the variable names, it can give you private variables and functions while exposing a limited API consisting of the returned object‘s properties and methods.

下面是之前例子的修改版,展示了如何在只暴露了一個公用方法的模組的情況下,建立相同的feature用模組化模式

Below is a revised version of the previous example, showing how we could create the same feature using the module pattern while only exposing one public method of the module, showItemByIndex().

// Using the module pattern for a jQuery feature$( document ).ready(function() {    var feature = (function() {        var items = $( "#myFeature li" );        var container = $( "<div class=‘container‘></div>" );        var currentItem = null;        var urlBase = "/foo.php?item=";         var createContainer = function() {            var item = $( this );            var _container = container.clone().appendTo( item );            item.data( "container", _container );        };         var buildUrl = function() {            return urlBase + currentItem.attr( "id" );        };         var showItem = function() {            currentItem = $( this );            getContent( showContent );        };         var showItemByIndex = function( idx ) {            $.proxy( showItem, items.get( idx ) );        };         var getContent = function( callback ) {            currentItem.data( "container" ).load( buildUrl(), callback );        };         var showContent = function() {            currentItem.data( "container" ).show();            hideContent();        };         var hideContent = function() {            currentItem.siblings().each(function() {                $( this ).data( "container" ).hide();            });        };         items.each( createContainer ).click( showItem );         return {            showItemByIndex: showItemByIndex        };    })();     feature.showItemByIndex( 0 );});

 

 

jQuery學習--Code Organization Concepts

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.