再次梳理AMD、CMD、CommonJS、ES6 Module的區別

AMD (RequireJS)

AMD全稱是Asynchronous Module Definition,即異步模塊加載機制。後來由該草案的做者以RequireJS實現了AMD規範,因此通常說AMD也是指RequireJS。css

RequireJS的基本用法

經過define來定義一個模塊,使用require能夠導入定義的模塊。vue

//a.js
//define能夠傳入三個參數,分別是字符串-模塊名、數組-依賴模塊、函數-回調函數
define(function(){
    return 1;
})
複製代碼
// b.js
//數組中聲明須要加載的模塊,能夠是模塊名、js文件路徑
require(['a'], function(a){
    console.log(a);// 1
});
複製代碼

RequireJS的特色 對於依賴的模塊,AMD推崇依賴前置,提早執行。也就是說,在define方法裏傳入的依賴模塊(數組),會在一開始就下載並執行。jquery

CMD ( SeaJS )

CMD是SeaJS在推廣過程當中生產的對模塊定義的規範,在Web瀏覽器端的模塊加載器中,SeaJS與RequireJS並稱,SeaJS做者爲阿里的玉伯。webpack

SeaJS的基本用法

//a.js
/* * define 接受 factory 參數,factory 能夠是一個函數,也能夠是一個對象或字符串, * factory 爲對象、字符串時,表示模塊的接口就是該對象、字符串。 * define 也能夠接受兩個以上參數。字符串 id 表示模塊標識,數組 deps 是模塊依賴. */
define(function(require, exports, module) {
  var $ = require('jquery');

  exports.setColor = function() {
    $('body').css('color','#333');
  };
});
複製代碼
//b.js
//數組中聲明須要加載的模塊,能夠是模塊名、js文件路徑
seajs.use(['a'], function(a) {
  $('#el').click(a.setColor);
});
複製代碼

SeaJS的特色

對於依賴的模塊,CMD推崇依賴就近,延遲執行。也就是說,只有到require時依賴模塊才執行。git

CommonJS

CommonJS規範爲CommonJS小組所提出,目的是彌補JavaScript在服務器端缺乏模塊化機制,NodeJS、webpack都是基於該規範來實現的。es6

CommonJS的基本用法

//a.js
module.exports = function () {
  console.log("hello world")
}
複製代碼
//b.js
var a = require('./a');

a();//"hello world"

//或者

//a2.js
exports.num = 1;
exports.obj = {xx: 2};

//b2.js
var a2 = require('./a2');

console.log(a2);//{ num: 1, obj: { xx: 2 } }
複製代碼

CommonJS的特色

  • 全部代碼都運行在模塊做用域,不會污染全局做用域;
  • 模塊是同步加載的,即只有加載完成,才能執行後面的操做;
  • 模塊在首次執行後就會緩存,再次加載只返回緩存結果,若是想要再次執行,可清除緩存
  • require返回的值是被輸出的值的拷貝,模塊內部的變化也不會影響這個值。

ES6 Module

ES6 Module是ES6中規定的模塊體系,相比上面提到的規範, ES6 Module有更多的優點,有望成爲瀏覽器和服務器通用的模塊解決方案。github

ES6 Module的基本用法

//a.js
var name = 'lin';
var age = 13;
var job = 'ninja';

export { name, age, job};
複製代碼
//b.js
import { name, age, job} from './a.js';

console.log(name, age, job);// lin 13 ninja
複製代碼
//或者

//a2.js
export default function () {
  console.log('default ');
}

//b2.js
import customName from './a2.js';
customName(); // 'default'
複製代碼

ES6 Module的特色(對比CommonJS)

  • CommonJS模塊是運行時加載,ES6 Module是編譯時輸出接口;
  • CommonJS加載的是整個模塊,將全部的接口所有加載進來,ES6 Module能夠單獨加載其中的某個接口;
  • CommonJS輸出是值的拷貝,ES6 Module輸出的是值的引用,被輸出模塊的內部的改變會影響引用的改變;
  • CommonJS this指向當前模塊,ES6 Module this指向undefined;

目前瀏覽器對ES6 Module兼容還不太好,咱們平時在webpack中使用的export/import,會通過babel轉換爲CommonJS規範。web

總結:

  • AMD 依賴前置,提早執行 (require.js),語法是define,require
  • CMD 依賴就近,延遲執行 (sea.js),語法是 define,seajs.use([],cb)
  • CommonJs 語法 module.exports=fn或者exports.a=1; 經過require('./a1')來引入
  • CommonJs 模塊首次執行會被緩存,再次加載只返回緩存結果,require返回的值是輸出值的拷貝(對於引用類型是淺拷貝)
  • es6 module 語法是 export {...}, import ...from..., export輸出的是值得引用。
  • NodeJS、webpack都是基於commonJs該規範來實現的

一些小問題

  • 在vue項目中可能存在,咱們A模塊導入了B模塊,C模塊也導入了B模塊,那麼B模塊在一個項目中被導入了屢次的場景,模塊化機制是如何處理的呢?

若是你是經過commonJS來require導入的模塊,那麼,首次導入會被緩存,後續的導入都是取的第一次的緩存結果。若是你是經過es6 import導入的模塊,那麼導入的都是值的引用。因此,導入屢次是在最終打包的時候,只打了一個而並不會重複打入的狀況。。數組

  • 若是深刻理解,先須要多使用,而後仍是須要把CommonJS的內部實現,與 es6的內部實現過一遍。

保留個問題: B導入模塊A,咱們本身如何實現?不用模塊化

  1. 把模塊A的代碼複製到了模塊B,顯然不靠譜,這樣會被複製出來的代碼量太大
  2. 動態建立script標籤,先讓A引入並執行。而後在引入B
  3. es6 Module是導出的值的引用。這個是如何實現的?
  4. 屢次重複導入如何處理?
  5. 循環引用如何處理?
  6. ......

總結-Commonjs 和 es6 module 的區別

  • Commonjs是同步導入,因用於服務端,文件都在本地,同步導入即便卡住主線程影響也不大,後者是異步導入,由於用於瀏覽器端,需下載文件,若是採用同步導入對渲染會有很大影響。
  • CommonJS 在導出時都是值的拷貝,就算導出的值變了,導入的值也不會變。若是想更新,必須從新導入一回。
  • ES Module 導入導出的值指向同一個內存地址。因此,導入值也會隨着導出值變化。
  • ES Module 會編譯成 require/exports來執行。
  • 一個導出的是值的拷貝,一個導出的是值的引用
  • 一個是同步導入,一個是異步導入

參考:juejin.im/post/5db95e…瀏覽器

請多多指點其中的問題點,使用的文章不少,難的是,真正的理解其內部機制與如何實現的?從模塊做者的角度考慮問題,多思考,學習才能掌握要領。從而實現本身的工具。

碼字不易,以爲還行,給star一下,您的star,是我前進的動力哈~

github

相關文章
相關標籤/搜索