AMD , CMD, CommonJS,ES Module,UMD

JavaScript模塊化

規範JavaScript的模塊定義和加載機制,下降了學習和使用各類框架的門檻,可以以一種統一的方式去定義和使用模塊,提升開發效率,下降了應用維護成本。api

  • 命名衝突
  • 文件依賴

差別

  • AMD 與 CMD:
    • AMD是 RequireJS 在推廣過程當中對模塊定義的規範化產出。
    • CMD是 SeaJS 在推廣過程當中對模塊定義的規範化產出。
    • CMD推崇依賴就近,AMD推崇依賴前置。
  • ES Module與CommonJS:
    • CommonJS模塊是對象,是運行時加載,運行時才把模塊掛載在exports之上(加載整個模塊的全部),加載模塊其實就是查找對象屬性。
    • ES Module不是對象,是使用export顯示指定輸出,再經過import輸入。此法爲編譯時加載,編譯時遇到import就會生成一個只讀引用。等到運行時就會根據此引用去被加載的模塊取值。因此不會加載模塊全部方法,僅取所需。
    • CommonJS 模塊輸出的是一個值的拷貝,ES6 模塊輸出的是值的引用。
    • CommonJS 模塊是運行時加載,ES6 模塊是編譯時輸出接口
  • CommonJS與AMD/CMD:
    • AMD/CMD是CommonJS在瀏覽器端的解決方案。
    • CommonJS是同步加載(代碼在本地,加載時間基本等於硬盤讀取時間)。
    • AMD/CMD是異步加載(瀏覽器必須這麼作,代碼在服務端)
  • UMD與AMD/CMD
    • UMD(Universal Module Definition)是AMD和CommonJS的糅合,跨平臺的解決方案。
    • AMD模塊以瀏覽器第一的原則發展,異步加載模塊。
    • CommonJS模塊以服務器第一原則發展,選擇同步加載,它的模塊無需包裝(unwrapped modules)。
    • UMD先判斷是否支持Node.js的模塊(exports)是否存在,存在則使用Node.js模塊模式。再判斷是否支持AMD(define是否存在),存在則使用AMD方式加載模塊。

用法

  • CommonJS
    • 導出使用module.exports,也能夠exports。就是在此對象上掛屬性。exports指向module.exports,即exports= module.exports
    • 加載模塊使用require('xxx')。相對、絕對路徑都可。默認引用js,能夠不寫.js後綴
// commonjs
module.exports.add = function add(params) {
    return ++params;
}
exports.sub = function sub(params) {
    return --params;
}
// index.js
var common = require('./commonjs');
console.log(common.sub(1));
console.log(common.add(1));
複製代碼
  • AMD/RequireJS
    • 定義模塊:define(id?, dependencies?, factory)
      • 依賴有三個默認的,即"require", "exports", "module"。順序個數都可視狀況
      • 若是忽略則factory默認此三個傳入參數
      • id通常是不傳的,默認是文件名
    • 加載模塊:require([module], factory)
// a.js
define(["b", "require", "exports"], function(b, require, exports) {
    console.log("a.js執行");
    console.log(b);
    // 暴露api可使用exports、module.exports、return
    exports.a = function() {
        return require("b");
    }
})
// b.js
define(function() {
    console.log('b.js執行');
    console.log(require);
    console.log(exports);
    console.log(module);
    return 'b';
})
// index.js
// 支持Modules/Wrappings寫法,注意dependencies得是空的,且factory參數不可空
define(function(require, exports, module) {
    console.log('index.js執行');
    var a = require('a');
    var b = require('b');
})
// index.js
require(['a', 'b'], function(a, b) {
    console.log('index.js執行');
})
複製代碼
  • CMD/SeaJS
    • 定義模塊:define(factory)
      • require, exports, module參數順序不可亂
      • 暴露api方法可使用exports、module.exports、return
      • 與requirejs不一樣的是,如果未暴露,則返回{},requirejs返回undefined
    • 加載模塊:require
    • 定義模塊無需列依賴,它會調用factory的toString方法對其進行正則匹配以此分析依賴
    • 預先下載,延遲執行
// a.js
define(function(require, exports, module) {
    console.log('a.js執行');
    console.log(require);
    console.log(exports);
    console.log(module);
})
// b.js
define(function(require, module, exports) {
    console.log('b.js執行');
    console.log(require);
    console.log(exports);
    console.log(module);
})
// index.js
define(function(require) {
    var a = require('a');
    var b = require('b');
    console.log(a);
    console.log(b);
})
複製代碼
  • ES Module
    • 輸出/export
    • 輸入/import
    • 輸入的模塊變量是不可從新賦值的,它只是個可讀引用,不過卻能夠改寫屬性
// 報錯1
export 1;
// 報錯2
const m = 1;
export m;

// 接口名與模塊內部變量之間,創建了一一對應的關係
// 寫法1
export const m = 1;
// 寫法2
const m = 1;
export { m };
// 寫法3
const m = 1;
export { m as module };
複製代碼
// 相似於對象解構
// module.js
export const m = 1;
// index.js
// 注意,這裏的m得和被加載的模塊輸出的接口名對應
import { m } from './module';
// 如果想爲輸入的變量取名
import { m as m1 }  './module';
// 值得注意的是,import是編譯階段,因此不能動態加載,好比下面寫法是錯誤的。由於'a' + 'b'在運行階段才能取到值,運行階段在編譯階段以後
import { 'a' + 'b' } from './module';
// 如果只是想運行被加載的模塊,以下
// 值得注意的是,即便加載兩次也只是運行一次
import './module';
// 總體加載
import * as module from './module';
複製代碼
  • 總結:
區別項 es模塊化 commonJS AMD
可用於服務端仍是瀏覽器 服務端和瀏覽器 服務端 瀏覽器
模塊依賴關係什麼時候肯定(即:什麼時候加載模塊) 編譯時 運行時 運行時
設計思想 儘可能的靜態化
模塊是否是對象 不是
是否總體加載模塊(即加載的全部方法)
是不是動態更新(即經過接口,能夠取到模塊內部實時的值) 是。es module輸出的是值的引用 不是。commonJS模塊輸出的是值的拷貝,不存在動態更新
模塊變量是不是隻讀的 v是。緣由:ES6 輸入的模塊變量,只是一個「符號鏈接」,因此這個變量是隻讀的,對它進行從新賦值會報錯。
  • commonJS模塊就是對象,總體加載模塊(即加載的全部方法)瀏覽器

  • ES6 模塊不是對象,而是經過export命令顯式指定輸出的代碼,再經過import命令輸入。bash

  • export命令規定的是對外的接口,必須與模塊內部的變量創建一一對應關係服務器

  • export語句輸出的接口,與其對應的值是動態綁定關係,即經過該接口,能夠取到模塊內部實時app

  • export命令和import命令能夠出如今模塊的任何位置,只要處於模塊頂層就能夠。 若是處於塊級做用域內,就會報錯,這是由於處於條件代碼塊之中,就無法作靜態優化了,違背了ES6模塊的設計初衷。框架

  • import命令具備提高效果,會提高到整個模塊的頭部,首先執行。異步

相關文章
相關標籤/搜索