ES6 以來,有了 module 的體系,替代了之前比較常用的 CommonJS 和 AMD 規範,使得在編譯時就能確定模組的依賴關係,同時使得前端在複雜專案時可以更好的分工和規範。

這篇文章主要介紹前端的模組化開發,主要包括 ES6 的 module 以及三個主要的模組化開發規範 CommonJS AMD 以及 CMD。

ES6 Module

ES6 的模組功能主要透過 export 以及 import 實現。模組中如果對外暴露介面就需要使用 export ,而如果想在模組中引用外部模組就需要使用 import。

典型的栗子就是 React,在 React 中我們十分常見的寫法就是:

import React from ‘react’;

import {func as fu, bar} from ‘。/my_module’;

。。。

export class MyClass extends React。Component {

。。。

}

當然我們不止是像 React 中匯出一個類,只要想把模組中的變數、方法等等暴露出去,都可以使用 export。

注意下面幾點:

1。在 import 中我們使用了大括號,其中大括號中的變數名必須和被匯入模組中對外暴露的藉口名稱相同,其實就是一個解構操作。

2。在 import 的時候我們使用了 as 來區別名,將輸入的 func 變數重新取名為 fu,這樣做的好處是如果同時引入的兩個模組中都含有 func 方法,透過區別名的方式就可以區分開來。其實在 export 的時候我們就可以使用別名。

3。同時注意 import 具有提升效果,因為是在編譯階段執行的,在程式碼執行之前。因此也不能使用一些執行時才能知道的語法結果,比如在 if else 語句之中判斷 import 哪個模組。

4。在匯出的時候可以使用export default,指定預設輸出。在使用 default 之後我們在 export 的時候就不需要再給自己的函式等等取名字了,可以使用匿名函式。這樣在 import 的時候可以自己隨意取名字。

比如:

import $, {clone} from ‘my_module’;

在 my_module 中的寫法就是:

export default function() { // 對應 import 中的 $

。。。

}

export function clone (obj) { // 對應 import 中的 {clone}

。。。

}

注意一個模組裡面只能有一個 default

CommonJS

CommonJS 主要是在 Node 伺服器端的規範。

CommonJS 也認為一個檔案就是一個模組,必須透過某種匯出才能使得別的模組使用該模組的對外介面。只是在 ES6 中使用 import export ,但是在 CommonJS 中使用 module。exports 物件進行匯出,並且一個模組中只有這一個統一的出口。在外部模組中,我們使用 require 進行載入,這個方法讀取一個檔案並且返回檔案中的 module。exports 物件。

例如:

定義一個模組 my_modules:

function bar() {

。。。

}

fucntion func() {

。。。。

}

module。exports = {

bar: bar,

func: func

}

載入模組:

var needModules = require(。/my_modules);

needModules。bar();

needModules。func();

主要注意幾點:

1。載入的檔案如果是“/”開頭表示記載絕對路徑的模組,以“。/”開頭表示載入相對路徑的模組檔案,兩者都不含的話表示從系統的核心模組或者 node_modules 已經安裝的模組。

2。模組載入會有快取,存放在 require。cache 之中,並且快取是根據絕對路徑是識別的,同樣的模組名放在不同的路徑之中多次 require 的時候還是不會重新載入模組,除非使用 delete require。cache。

3。CommonJS是同步載入的,因此更適合伺服器端。只有載入完成之後才能進行下面的操作。因為在伺服器端模組檔案一般存放在本地,再加上有快取,載入速度十分快。因此這種就不適合用在瀏覽器端,瀏覽器端的各個 script 標籤中的檔案來自各個伺服器,如果上個模組記載的時間很長,就會導致瀏覽器“假死”,因此瀏覽器端我們採用另外一種非同步的載入方式–AMD。

AMD

AMD(Asynchronous Module Definition)就是非同步載入模組,模組的載入不會影響後面程式碼的執行。所以依賴這個模組的程式碼都在一個回撥函式中,等到所有模組載入完成之後就會執行這個回撥函式。最常見的支援 AMD 規範的就是 RequireJS。

在 AMD 中,模組的載入也是使用 require([dependencies], function(){}) 語句,但是不同於 CommonJS,它的引數除了有需要載入的模組檔案之後,還需要約定一個回撥函式,由這個回撥函式去規定當模組都載入完成之後執行什麼操作,載入的模組會以引數形式傳入該回調函式函式,從而在回撥函式內部就可以使用這些模組。

而模組的定義主要是使用 define(id?, dependencies, factory)語句,其中 id 可選,定義模組的標識。 dependencies 可選引數,表示當前模組依賴的模組,是一個數組。 factory 是一個工廠方法,表示模組初始化需要執行的函式或者物件。一般我們會在這個 factory 中 return 出一個物件來暴露出我們的對外介面等等。

舉個栗子:

定義一個模組 my_modules

define([‘math’], function() {

function bar() {

。。。

}

return {

bar: bar

};

});

載入模組

require([my_modules], function(my) {

my。bar();

})

CMD

CMD(Common Module Definition)就是通用模組定義。CMD 是從國內發展出去的,實現主要是 SeaJS, 和 AMD 都是解決非同步載入以及模組依賴的問題,但是在模組的定義方式上面有點不同。

在 CMD 中,定義模組使用 define(id?, deps?,factory),其中 id、depes 可以省略,字串 id 表示模組標識,陣列 deps 是模組依賴。當 factory 是一個函式的時候表示模組的構造方法,預設接受三個引數 require、export、module。

再舉個栗子:

定義一個模組 my_module

define(function(require, export, module) {

var person = {name: ‘abby’, age: 20};

var _ = require(‘lodash’); // 需要的時候才去載入模組 lodash

var shallow = _clone(person);

// 支援非同步載入模組,當多個模組載入完成之後才執行回撥

require。async(‘。/a’, 。/b‘, function(a, b) {

a。doSomething();

b。doSomething();

});

bar() {

。。。

}

// 在匯出模組的時候支援了 CommonJS 和 AMD 的寫法。

return {

bar: bar

};

或者

module。exports = {

bar: bar

}

或者

exports。bar = bar //此時注意不能寫成物件形式

})

AMD CMD 區別

1。AMD推崇依賴前置,在定義模組的時候就宣告依賴的模組。CMD 推崇依賴就近,只有在需要用的時候才去require 執行。

2。對於依賴的模組,AMD 提前執行,但是 CMD 的思想是 lazy loading, 延遲執行。但是現 RequireJS 2。0 也改成可以根據不同的寫法進行延遲執行

UMD

UMD(Universal Module Definition)就是通用模組定義規範,是一種相容 CommonJS 以及 AMD 的寫法,具體實現就是使用一個立即執行的函式,然後將當前的執行環境 this 以及 factory 傳過去,它會優先判斷是否支援 AMD 環境,然後判斷是否支援 CommonJS 環境來載入模組。

舉個栗子:

(function (root, factory) {

if (typeof define === ’function‘ && define。amd) {

// AMD

define([’jquery‘, ’lodash‘], factory);

} else if (typeof exports === ’object‘) {

// CommonJS

module。exports = factory(require(’jquery‘), require(’lodash‘));

} else {

// 在瀏覽器裡面的全域性變數即 window

root。returnExports = factory(root。jQuery, root。_);

}

}(this, function ($, _) {

function a(){}; // 沒被返回,私有方法

function b(){}; // 被返回了,公有方法

function c(){}; // 被返回了,公有方法

//暴露對外的介面

return {

b: b,

c: c

}

}));

本文只是很淺顯的介紹,具體的用法可以參考文件。具體專案中使用哪種分情況而定。

(最近少女心爆棚,又做了張粉圖。。其實我喜歡黑白。。噗嗤

參考資料:

Module

import

export

CommonJS規範

Why AMD

Javascript模組化程式設計(二):AMD規範

Javascript模組化程式設計(三):require。js的用法

前端模組化

CMD 模組定義規範 #242

AMD 和 CMD 的區別有哪些

UMD Github

What Is AMD, CommonJS, and UMD?