天天看點

AMD , CMD , CommonJs 和 ES6 對比1.CommonJS2.AMD3. CMD4. AMD和CMD的差別5. ES6

1.CommonJS

1.1 基本概念

  1. 為JS的表現來制定規範,因為js沒有子產品的功能是以CommonJS應運而生,它希望js可以在任何地方運作,不隻是浏覽器中。
  2. 同步
  3. CommonJS規範 通過model.exports定義的,在前端浏覽器中并不支援
  4. NodeJS是CommonJS規範的實作,webpack 也是以CommonJS的形式來書寫的。
  5. CommonJS定義的子產品分為: 子產品引用(require) ; 子產品定義(exports) ; 子產品辨別(module)

require()用來引入外部子產品;exports對象用于導出目前子產品的方法或變量,唯一的導出口;module對象就代表子產品本身。

var foo = require('foo.js');
var count = 1;
var plusCount = () => {
  foo.add(count);
};
module.exports = {
  count,
  plusCount
};
           

浏覽器不相容CommonJS的根本原因,也正是在于缺少四個Node.js環境的變量。

  • module
  • exports
  • require
  • global

1.2 特點

  • 對于基本資料類型,屬于複制。即會被子產品緩存。同時,在另一個子產品可以對該子產品輸出的變量重新指派。
  • 對于複雜資料類型,屬于淺拷貝。由于兩個子產品引用的對象指向同一個記憶體空間,是以對該子產品的值做修改時會影響另一個子產品。
// b.js
let num = 1;
let obj = {
    name: 'hcd'
};
setTimeout(() => {
  console.log('b.js-num:', num);
  console.log('b.js-name:', obj.name);
}, 1000)
module.exports = {
  num,
  obj
}



// a.js
let mod = require('./b.js')
mod.num = 2;
mod.obj.name = 'newName'
console.log('a.js-num:', mod.num);
console.log('a.js-name:', mod.obj.name);



//運作node
node a.js
a.js-num:  2
a.js-name: newName
b.js-num:  1         // 1秒後
b.js-name: newName  // 1秒後
           
  • 當使用require指令加載某個子產品時,就會運作整個子產品的代碼。
  • 當使用require指令加載同一個子產品時,不會再執行該子產品,而是取到緩存之中的值。也就是說,CommonJS子產品無論加載多少次,都隻會在第一次加載時運作一次,以後再加載,就傳回第一次運作的結果,除非手動清除系統緩存。
  • 循環加載時,屬于加載時執行。即腳本代碼在require的時候,就會全部執行。一旦出現某個子產品被”循環加載”,就隻輸出已經執行的部分,還未執行的部分不會輸出。
// a.js
exports.done = false
let b = require('./b.js')
console.log('a.js-1', b.done)
exports.done = true
console.log('a.js-2', '執行完畢')




// b.js
exports.done = false
let a = require('./a.js')
console.log('b.js-1', a.done)
exports.done = true
console.log('b.js-2', '執行完畢')




// c.js
let a = require('./a.js')
let b = require('./b.js')

console.log('c.js-1', '執行完畢', a.done, b.done)



運作node c.js
b.js-1 false
b.js-2 執行完畢
a.js-1 true
a.js-2 執行完畢
c.js-1 執行完畢 true true
           

說明:

  1. 在Node.js中執行c子產品。此時遇到require關鍵字,執行a.js中所有代碼。
  2. 在a子產品中exports之後,通過require引入了b子產品,執行b子產品的代碼。
  3. 在b子產品中exports之後,又require引入了a子產品,此時執行a子產品的代碼。
  4. 因為 某個子產品被”循環加載”,就隻輸出已經執行的部分,還未執行的部分不會輸出。a子產品隻執行exports.done =
  5. false這條語句。
  6. 回到b子產品,列印b.js-1, exports, b.js-2。b子產品執行完畢
  7. 回到a子產品,接着列印a.js-1, exports, b.js-2。a子產品執行完畢
  8. 回到c子產品,接着執行require,需要引入b子產品。由于在a子產品中已經引入過了,是以不會再執行該子產品,而是取到緩存之中的值,直接就可以輸出值了。 結束。

2.AMD

2.1誕生背景

基于commonJS規範的nodeJS出來以後,服務端的子產品概念已經形成,很自然地,大家就想要用戶端子產品。而且最好兩者能夠相容,一個子產品不用修改,在伺服器和浏覽器都可以運作。但是,由于一個重大的局限,使得CommonJS規範不适用于浏覽器環境。因為會有一個很大的問題:

 var math = require('math');

 math.add(2, 3);
           

第二行math.add(2, 3),在第一行require(‘math’)之後運作,是以必須等math.js加載完成。也就是說,如果加載時間很長,整個應用就會停在那裡等。您會注意到 require 是同步的。

這對伺服器端不是一個問題,因為所有的子產品都存放在本地硬碟,可以同步加載完成,等待時間就是硬碟的讀取時間。但是,對于浏覽器,這卻是一個大問題,因為子產品都放在伺服器端,等待時間取決于網速的快慢,可能要等很長時間,浏覽器處于”假死”狀态。

是以,浏覽器端的子產品,不能采用”同步加載”(synchronous),隻能采用”異步加載”(asynchronous)。這就是AMD規範誕生的背景。

CommonJS是主要為了JS在後端的表現制定的,他是不适合前端的,AMD(異步子產品定義)出現了,它就主要為前端JS的表現制定規範。

2.2AMD

AMD (異步子產品定義Asynchronous Module Definition) :是require.js在推廣過程中對子產品定義的規範化産出

  • AMD:

子產品本身和子產品之間的引用可以被異步的加載,是一個概念

先引入的子產品,後使用的引用子產品的方法,是以我們稱之為依賴前置

  • AMD優點:

包括異步的調用和本身的高擴充性,

它實作了解耦,子產品在代碼中也可通過識别号進行查找。

  • require.js

是對AMD這個概念的實作,

require.js的誕生,就是為了解決這兩個問題:

實作js檔案的異步加載,避免網頁失去響應;

管理子產品之間的依賴性,便于代碼的編寫和維護。

  • 官網:

http://www.requirejs.cn/

define(['./package/lib.js'], function(lib) {
      function say(){
           lib.log('this is fn');
       }
       return {
           say:say
       }; 
});
           

說明:

  1. ./package/lib.js使我們依賴的子產品,回調函數中參數lib表示的是引入的子產品的所有方法和屬性,我們可以調用
  2. 後來我們又在目前子產品定義了say方法,并return輸出
  3. 可以看到我們是先引入的子產品,後使用的引用子產品的方法,是以我們稱之為依賴前置

3. CMD

Cmd是SeaJs在推廣過程中對子產品定義的規範化産出

Cmd: 同步子產品定義,是一個概念

SeaJs: SeaJS的作者是前淘寶UED,現支付寶前端工程師玉伯。

原則: 依賴就近原則

// 所有的子產品通過define定義
   define(function (require, exports, module) {
       //通過require引入依賴,并不是AMD的前置依賴,而是依賴就近原則,在哪裡使用,在哪裡引入,就是同步的概念,即用即傳回
           var $ = require('jquery');
           //輸出子產品中定義的方法
           exports.sayHello = function () {
               $('#hello').toggle('slow');
           };
       });
           

4. AMD和CMD的差別

AMD 通過 require.js實作

CMD 通過 sea.js實作

相同處 :

RequireJS 和 Sea.js 都是子產品加載器,倡導子產品化開發理念,核心價值是讓 JavaScript 的子產品化開發變得簡單自然。

不同之處 :

  • 定位有差異。RequireJS 想成為浏覽器端的子產品加載器,同時也想成為 Rhino / Node 等環境的子產品加載器。Sea.js則專注于 Web 浏覽器端,同時通過 Node 擴充的方式可以很友善跑在 Node 環境中。
  • 遵循的規範不同。RequireJS 遵循 AMD(異步子產品定義)規範,Sea.js 遵循 CMD(通用子產品定義)規範。規範的不同,導緻了兩者 API 不同。Sea.js 更貼近 CommonJS Modules/1.1 和 Node Modules 規範。
  • RequireJS 是依賴前置,Sea.js是依賴就近
  • 對開發調試的支援有差異。Sea.js 非常關注代碼的開發調試,有 nocache、debug 等用于調試的插件。RequireJS無這方面的明顯支援。
  • 插件機制不同。RequireJS 采取的是在源碼中預留接口的形式,插件類型比較單一。Sea.js 采取的是通用事件機制,插件類型更豐富。

總之,如果說 RequireJS 是 Prototype 類庫的話,則 Sea.js 緻力于成為 jQuery 類庫。

5. ES6

上面的AMD,CMD,CommonJs都是ES5時期的。

ES6中無需引入别的js檔案,ES6 在語言标準的層面上,實作了子產品功能,而且實作得相當簡單,完全可以取代 CommonJS 和 AMD 規範,成為浏覽器和伺服器通用的子產品解決方案。

ES6 子產品的設計思想是盡量的靜态化,使得編譯時就能确定子產品的依賴關系,以及輸入和輸出的變量。CommonJS 和 AMD 子產品,都隻能在運作時确定這些東西。

我這裡隻是簡單說一下,推薦阮一峰老師的學習網站,裡面有非常詳細的講解:

http://es6.ruanyifeng.com/#docs/module

————————————————

版權聲明:本文為CSDN部落客「南張門」的原創文章,遵循CC 4.0 BY-SA版權協定,轉載請附上原文出處連結及本聲明。

原文連結:https://blog.csdn.net/haochangdi123/article/details/80408874