使用AMD,CommonJS和ES Harmony編寫模塊化JavaScript代碼(ES Harmony)

原文:https://addyosmani.com/writing-modular-js/

ES Harmony 模塊化的未來


TC39,是負責定義ECMAScript語法和語義標準的機構,由一羣精英的開發人員組成,不斷進行標準規範的版本迭代。在過去幾年裏,一些開發人員(像Alex Russell)已經將探索的重心放在讓JavaScript適合大型項目開發的解決方案上,並且也深深的體會到對模塊化JS編程的強烈需求。

因此,已經提出了一些針對這一需求的改進方案。其中包括可以適用於客戶端和服務端的靈活的模塊系統模塊加載器以及一些其他的特性。在這一章裏,我將會針對這些即將發佈的新特性,展示對應的示例代碼,期望能夠讓你對其有最基本的瞭解。

注意:雖然Harmony還是在提案階段(譯者注:請以當前最新的ES規範爲準),但是多虧了Chrome的Traceur 編譯器,你已經可以去嘗試這些新的功能特性了。通過入門教程,可以在幾分鐘內上手。如果你對這個項目十分感興趣的話,那麼可以嘗試閱讀JSConf描述(譯者注:原文中存在鏈接,但打開後404)。

具有imports和exports的模塊(Modules)

如果你已經讀過了AMD和CJS模塊標準的話,那麼應該熟悉了imports(module dependencies 模塊依賴)和exports(或者是可被其他模塊訪問的公共API/變量)的的概念。在下一版的ES規範(ES.next)中,上述依賴概念被簡潔地定義爲import關鍵字來實現。export和我們期待的並沒有什麼不同,我想大多數的開發者通過下面的示例,就能很快的理解。

  • import聲明,將模塊的exports作爲局部變量進行綁定,並且可能會通過重命名以避免變量的衝突。
  • export聲明,將本地綁定的模塊聲明爲外部可見的,因此其他的模塊可以訪問該模塊的exports,但不能修改。有趣的是,模塊可以暴露(export)它的子模塊,而不能暴露在其他位置定義的模塊。同時,可以將暴露的方法或變量重命名,而無需使用其本地的名稱。
module staff{
    // specify (public) exports that can be consumed by
    // other modules
    export var baker = {
        bake: function( item ){
            console.log('Woo! I just baked ' + item);
        }
    }   
}

module skills{
    export var specialty = "baking";
    export var experience = "5 years";
}

module cakeFactory{

    // specify dependencies
    import baker from staff;

    // import everything with wildcards
    import * from skills;

    export var oven = {
        makeCupcake: function( toppings ){
            baker.bake('cupcake', toppings);
        },
        makeMuffin: function( mSize ){
            baker.bake('muffin', size);
        }
    }
}

從遠程資源加載模塊

ES Harmony的模塊化協議同樣適用於基於遠程的模塊(例如,第三方的API封裝),使其能夠簡潔的從外部位置加載模塊。下面就是遠程拉取我們之前定義的模塊並且使用的例子

module cakeFactory from 'http://addyosmani.com/factory/cakes.js';
cakeFactory.oven.makeCupcake('sprinkles');
cakeFactory.oven.makeMuffin('large');

模塊加載器API

模塊加載器描述了嚴格控制情況下,加載模塊的推薦動態API。支持的加載器包括加載模塊的函數load(url, moduleInstance, error),創建模塊的函數createModule(object, globalModuleReferences)以及其他的方法。下面是在模塊中動態加載我們之前定義的模塊的示例。與上面通過遠程資源加載模塊不同,模塊加載器API更適合動態加載的情況。

Loader.load('http://addyosmani.com/factory/cakes.js',
    function(cakeFactory){
        cakeFactory.oven.makeCupcake('chocolate');
    });

服務端類似CommonJS的模塊

對於面向服務的開發人員,ES.next的模塊系統並非僅僅拘泥於適用於瀏覽器的模塊。下面的例子,展示了在服務端使用的類似CommonJS的模塊。

// io/File.js
export function open(path) { ... };
export function close(hnd) { ... };
// compiler/LexicalHandler.js
module file from 'io/File';

import { open, close } from file;
export function scan(in) {
    try {
        var h = open(in) ...
    }
    finally { close(h) }
}
module lexer from 'compiler/LexicalHandler';
module stdlib from '@std';

//... scan(cmdline[0]) ...

具有構造器,Getter方法和Setter方法的類

類的概念一直是純粹主義者爭論的焦點,迄今爲止,我們已經使用了很多方法來模擬類的功能,包括利用原生JavaScript的原型系統,或者使用框架,或者利用抽象等等,這些都可以提取爲相同的原型行爲。

在Harmony中,類將成爲語言的一部分,包括了構造器,和私有性。在隨後的示例中,我加入了行內註釋,以幫助你更好的理解類是如何構建的。同時你會發現這裏並沒有使用function關鍵字。這並非是拼寫錯誤:TC39希望開發人員能夠更爲簡潔的編寫代碼,因此爲了減少隨意濫用function的情況,而做出了極大的努力。

class Cake{

    // We can define the body of a class' constructor
    // function by using the keyword 'constructor' followed
    // by an argument list of public and private declarations.
    constructor( name, toppings, price, cakeSize ){
        public name = name;
        public cakeSize = cakeSize;
        public toppings = toppings;
        private price = price;

    }

    // As a part of ES.next's efforts to decrease the unnecessary
    // use of 'function' for everything, you'll notice that it's
    // dropped for cases such as the following. Here an identifier
    // followed by an argument list and a body defines a new method

    addTopping( topping ){
        public(this).toppings.push(topping);
    }

    // Getters can be defined by declaring get before
    // an identifier/method name and a curly body.
    get allToppings(){
        return public(this).toppings;
    }

    get qualifiesForDiscount(){
        return private(this).price > 5;
    }

    // Similar to getters, setters can be defined by using
    // the 'set' keyword before an identifier
    set cakeSize( cSize ){
        if( cSize < 0 ){
            throw new Error('Cake must be a valid size - 
            either small, medium or large');
        }
        public(this).cakeSize = cSize;
    }
}

ES Harmony總結

像你看到的那樣,即將到來的ES.next會伴隨這許多令人興奮的特性。雖然在現在可以使用Traceur來嘗試新的特性,但是立刻將Harmony使用到當前的項目中,並非是一個優越的選擇(就目前來看)。這其中仍然有些問題存在,例如官方規範的變動,以及在跨瀏覽器兼容性可能存在的問題(例如IE會在運行ES Harmony一段時間後鎖死進程)。所以最好等到規範最終的確定,並且囊括了AMD(瀏覽器模塊)和CJS(服務端模塊)。

相關閱讀
A First Look At The Upcoming JavaScript Modules
David Herman On JavaScript/ES.Next (Video)
ES Harmony Module Proposals
ES Harmony Module Semantics/Structure Rationale
ES Harmony Class Proposals

總結和後續推薦閱讀

在文中我們大概瞭解了幾種可選擇的用於編寫模塊化JavaScript代碼的現代化模塊規範。這些模塊相較於傳統的模塊模式具有很大優勢:包括避免了開發人員針對每個創建的模塊去定義全局變量,更好的支持動態和靜態的依賴管理,通過腳本加載器提高可配型,在服務端使模塊具有更優的可配行,等等。

簡而言之,我建議嘗試下當前被推薦的這些規範,它們爲構建可複用的模塊化功能提供了更強的效率和靈活性。

這就是全部內容,如果你有任何疑問關於這些主題,歡迎在twitter上與我聯繫,我將盡我的最大努力回答!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章