一. 什麼是模塊化
模塊化是一種將系統分離成獨立功能部分的方法,可將系統分割成獨立的功能部分,嚴格定義模塊接口、模塊間具備透明性。
js中的模塊化方法,大體分爲如下幾個:commonJS, amd, cmd, umd, esModule。下面咱們來逐個擊破。
二. CommonJS
commonjs規範爲js提供一個美好的願景-但願js可以在任何地方都去運行。它的定義也十分簡單,主要分爲:模塊引用、模塊定義、模塊標識。
1. 模塊引用
在commonjs中,使用require方法引用模塊javascript
2. 模塊定義
在模塊中,上下文提供了exports對象,用來導出模塊的方法或變量。另外還存在一個module對象,它表明着模塊自己。在node.js中,一個文件就是一個模塊。具體導出方式:
module.exports.test = () => {
return "test";
}
3. 模塊標識
模塊標識實際上就是require方法的參數,即引入模塊的路徑。java
commonjs的優勢:
- 全部代碼都運行在模塊做用域,不會污染全局
- 模塊的加載只須要運行一次,之後都從緩存中加載
- 模塊加載是同步的,按照代碼中出現的順序
- 簡單易用
commonjs缺點:
- 同步加載的方法,不適合瀏覽器環境。瀏覽器環境瓶頸在於帶寬,服務器環境瓶頸在於cpu和內存。瀏覽器環境須要異步加載模塊。
- 非es官方標準
實現:node.js
三. AMD
amd規範是commonjs的延伸,amd全名:異步模塊定義,針對瀏覽器設計。定義一套模塊異步加載規範,來解決commonjs同步加載問題。
它的規範只有1個定義:
define(id: string, dependencies: Array<string>, factory: Function)
舉個🌰
定義:
define("module", ["module1", "module2"], function(m1, m2) {
return "test";
})
使用:
require(["module", "../file"], function(module, file) { /* ... */ });
與commonjs區別:
- amd使用define定義模塊,而在node實現中是隱式包裝。
- 內容須要經過返回(return)的方式實現導出。
AMD優勢:
AMD缺點:
- 是commonjs模塊化規範的一種妥協方式
- 非es官方標準
實現:require.js
四. CMD
cmd規範由玉伯提出,與amd主要區別在於:定義模塊和依賴模塊引入的部分。
- amd須要聲明模塊的時候,指定全部依賴。
- cmd更接近node.js對commonjs規範的定義:define(factory),依賴部分, cmd能夠動態引入:
define(function(require, exports, module) {
})
CMD優勢:
CMD缺點:
- 依賴 SPM 打包,模塊的加載邏輯偏重
- 非es官方標準
五. UMD
爲了讓同一個模塊,可以在瀏覽器環境和服務器環境可以兼容。umd是commonjs和amd的結合體。其代碼以下:
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD
define([], factory);
} else if (typeof exports === 'object') {
// commonjs,如 nodejs
module.exports = factory();
} else {
// root == window or global
root.returnExports = factory();
}
}(this, function () {
return {};
}));
UMD優勢:
六. ES Module
es module 是es官方提供的js模塊化標準方案,相對社區上的amd, cmd,umd等,它是標準。其設計思想,儘可能靜態化,這樣編譯時,才能肯定依賴關係。這也是webpack 搖樹可以實現的關鍵緣由。
es module使用 import 導入模塊。 使用 export 導出模塊。
舉個🌰
// a.js
let foo = "hello";
export foo;
// b.js
import { foo } from "a";
console.log(foo); // hello
commonjs與es module區別:
|
commonjs |
es module |
導出值 |
拷貝導出值,模塊內部值變化不影響引用值 |
import是值的引用 |
運行機制 |
運行時加載依賴,加載的是一個對象 |
編譯時加載,加載的是模塊的接口定義,在代碼靜態解析時會生成 |