如何正確理解javascript的模塊化

模塊化在項目中十分的重要,一個複雜的項目確定有不少類似的功能模塊,若是每次都須要從新編寫模塊確定既費時又耗力。可是引用別人編寫模塊的前提是要有統一的「打開姿式」,若是每一個人有各自的寫法,那麼確定會亂套,下面介紹幾種JS的模塊化的規範。jquery

一:模塊化進程一:script標籤瀏覽器

這是最原始的 JavaScript 文件加載方式,若是把每個文件看作是一個模塊,那麼他們的接口一般是暴露在全局做用域下,也就是定義在 window 對象中,不一樣模塊的接口調用都是一個做用域中,一些複雜的框架,會使用命名空間的概念來組織這些模塊的接口。服務器

缺點:app

一、污染全局做用域框架

二、開發人員必須主觀解決模塊和代碼庫的依賴關係異步

三、文件只能按照script標籤的書寫順序進行加載模塊化

四、在大型項目中各類資源難以管理,長期積累的問題致使代碼庫混亂不堪函數

二:模塊化進程二:CommonJS規範學習

該規範的核心思想是容許模塊經過require方法來同步加載所要依賴的其餘模塊,而後經過 exports 或 module.exports 來導出須要暴露的接口。ui

?

1

2

3

4

require("module");

require("../file.js");

exports.doStuff = function(){};

module.exports = someValue;

優勢:

一、簡單並容易使用

二、服務器端模塊便於重用

缺點:

一、同步的模塊加載方式不適合在瀏覽器環境中,同步意味着阻塞加載,瀏覽器資源是異步加載的

二、不能非阻塞的並行加載多個模塊

module.exports與exports的區別

一、exports 是指向的 module.exports 的引用

二、module.exports 初始值爲一個空對象 {},因此 exports 初始值也是 {}

三、require() 返回的是 module.exports 而不是 exports

exports示例:

?

1

2

3

4

5

6

7

// app.js

var circle = require('./circle');

console.log(circle.area(4));

// circle.js

exports.area = function(r){

 return r * r * Math.PI;

}

module.exports示例:

?

1

2

3

4

5

6

7

// app.js

var area = require('./area');

console.log(area(4));

// area.js

module.exports = function(r){

 return r * r * Math.PI;

}

錯誤的狀況:

?

1

2

3

4

5

6

7

// app.js

var area = require('./area');

console.log(area(4));

// area.js

exports = function(r){

 return r * r * Math.PI;

}

實際上是對 exports 進行了覆蓋,也就是說 exports 指向了一塊新的內存(內容爲一個計算圓面積的函數),也就是說 exports 和 module.exports 再也不指向同一塊內存,也就是說此時 exports 和 module.exports 毫無聯繫,也就是說 module.exports 指向的那塊內存並無作任何改變,仍然爲一個空對象{},也就是說area.js導出了一個空對象,因此咱們在 app.js 中調用 area(4) 會報 TypeError: object is not a function 的錯誤。

總結:當咱們想讓模塊導出的是一個對象時, exports 和 module.exports 都可使用(但 exports 也不能從新覆蓋爲一個新的對象),而當咱們想導出非對象接口時,就必須也只能覆蓋 module.exports 。

三:模塊化進程三:AMD規範

因爲瀏覽器端的模塊不能採用同步的方式加載,會影響後續模塊的加載執行,所以AMD(Asynchronous Module Definition異步模塊定義)規範誕生了。

AMD標準中定義瞭如下兩個API

一、require([module], callback);
二、define(id, [depends], callback);

require接口用來加載一系列模塊,define接口用來定義並暴露一個模塊。

示例:

?

1

2

3

4

define("module", ["dep1", "dep2"], function(d1, d2){

 return someExportedValue;

});

require(["module", "../file"], function(module, file){ /* ... */ });

優勢:

一、適合在瀏覽器環境中異步加載模塊

二、能夠並行加載多個模塊

缺點:

一、提升了開發成本,代碼的閱讀和書寫比較困難,模塊定義方式的語義不暢

二、不符合通用的模塊化思惟方式,是一種妥協的實現

四:模塊化進程四:CMD規範

CMD(Common Module Definition)規範和AMD很類似,儘可能保持簡單,並與CommonJS和Node.js的 Modules 規範保持了很大的兼容性。在CMD規範中,一個模塊就是一個文件。

示例:

?

1

2

3

4

5

6

define(function(require, exports, module){

 var $ = require('jquery');

 var Spinning = require('./spinning');

 exports.doSomething = ...

 module.exports = ...

})

優勢:

一、依賴就近,延遲執行

二、能夠很容易在 Node.js 中運行

缺點:

一、依賴 SPM 打包,模塊的加載邏輯偏重

AMD和CMD的區別

AMD和CMD起來很類似,可是仍是有一些細微的差異,讓咱們來看一下他們的區別在哪裏:

一、對於依賴的模塊,AMD是提早執行,CMD是延遲執行。

二、AMD推崇依賴前置;CMD推崇依賴就近,只有在用到某個模塊的時候再去require。看代碼:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

// AMD

define(['./a', './b'], function(a, b){ // 依賴必須一開始就寫好

  a.doSomething() 

  // 此處略去 100 行

  b.doSomething() 

  ...

});

// CMD

define(function(require, exports, module){

  var a = require('./a'

  a.doSomething() 

  // 此處略去 100 行

  var b = require('./b')

  // 依賴能夠就近書寫

  b.doSomething()

  // ...

});

三、AMD 的 API 默認是一個當多個用,CMD 的 API 嚴格區分,推崇職責單一。

五:模塊化進程五:ES6模塊化

EcmaScript6標準增長了JavaScript語言層面的模塊體系定義。ES6 模塊的設計思想,是儘可能的靜態化,使得編譯時就能肯定模塊的依賴關係,以及輸入和輸出的變量。CommonJS和AMD模塊,都只能在運行時肯定這些東西。

在 ES6 中,咱們使用export關鍵字來導出模塊,使用import關鍵字引用模塊。須要說明的是,ES6的這套標準和目前的標準沒有直接關係,目前也不多有JS引擎能直接支持。所以Babel的作法其實是將不被支持的import翻譯成目前已被支持的require。

儘管目前使用import和require的區別不大(本質上是一回事),但依然強烈推薦使用import關鍵字,由於一旦JS引擎可以解析ES6的import關鍵字,整個實現方式就會和目前發生比較大的變化。若是目前就開始使用import關鍵字,未來代碼的改動會很是小。

示例:

?

1

2

3

import "jquery";

export functiondoStuff(){}

module "localModule" {}

優勢:

一、容易進行靜態分析

二、面向將來的 EcmaScript 標準

缺點:

一、原生瀏覽器端尚未實現該標準

二、全新的命令字,新版的 Node.js才支持

以上就是本文的所有內容,但願本文的內容對你們的學習或者工做能帶來必定的幫助,同時也但願多多支持腳本之家!

原博客地址:

http://www.jb51.net/article/107245.htm

相關文章
相關標籤/搜索