早期前端沒有模塊化的概念,基本就是直接在HTML頁面上寫或者JSP/PHP等頁面上寫。後面出現了傳統的模塊化方法通過添加全局變量、命名空間方式、閉包封裝的形式實現模塊化,但是不能解決依賴困難問題。後來出現了commonJS(同步加載)和AMD(異步加載)兩種模塊化規範,其中AMD主要用於前端開發,流行庫爲RequireJS,而commonJS用於後臺和Node.js,CMD是SeaJS在推廣時形成的規範。
AMD
1、僅僅需要在全局環境下定義require和define,不需要其他的全局變量
2、通過文件路徑或模塊自己聲明的模塊名定位模塊
3、模塊實現聲明依賴,依賴的加載與執行均由加載器操作
4、提供了打包工具自動分析依賴併合並
典型用法:
define(function (require) {
//通過相對路徑獲得依賴模塊
const bar = require('./bar');
//模塊產出
return function () {
//...
};
});
CommonJS
相比於AMD的模塊格式,CommonJS的模塊格式更簡潔,而且可以更方便地實現前後端代碼共用,因爲Node.js就是採用的CommonJS規範
典型用法:
//通過相對路徑獲得依賴模塊
const bar = require('./bar');
//模塊產出
module.exports = function () {
//...
};
module.exports = {
//...
};
CMD
CMD是SeaJS推廣時形成的一種規範,它與AMD有點相似,但兼容CommoJS的模塊。
典型用法:
define(function(require, exports, module) {
var $ = require('jquery');
var Spinning = require('./spinning');
exports.doSomething = ...
module.exports = ...
})
ES6模塊化
相比於AMD或是CommonJS規範,ES6的模塊化語句更清晰易懂,且其引用和暴露的方式更多樣。
典型用法:
//通過相對路徑獲得依賴模塊
import {bar, far} from './bar'
//模塊產出
export let bar = 3;
export default function () {
//...
}
對比CommonJS和ES6模塊化
1、CommonJS模塊輸出的是一個值的複製,ES6模塊輸出的是值的引用(可被修改)
2、CommonJS模塊是運行是加載,ES6模塊是編譯時輸出接口
第一個差異主要是說,CommonJS的一旦輸出,模塊內部的變化不會影響到這個值;而JS引擎對腳本靜態分析的時候,遇到模塊加載命令import就會生成一個只讀引用,等到腳本真正執行時,在根據這個只讀引用到被加載的模塊中取值,即ES6模塊是動態引用,且不會緩存值,模塊內部導致原始值變了,import加載的值也會跟着變。
第二個差異是因爲CommonJS加載的是一個對象(即module.exports屬性),該對象只有在腳本運行結束時纔會生生。而ES6模塊不是對象,它的對外接口只是一種靜態定義,在代碼靜態解析階段就會生成。
對比CMD和AMD
1、對於依賴的模塊AMD是提前執行,CMD是延遲執行。不過RequireJS從2.0開始,也改成可以延遲執行(根據寫法不同,處理方式不通過)。
2、CMD推崇依賴就近,AMD推崇依賴前置。
//AMD
define(['./a','./b'], function (a, b) {
//依賴一開始就寫好
a.test();
b.test();
});
//CMD
define(function (requie, exports, module) {
//依賴可以就近書寫
var a = require('./a');
a.test();
//軟依賴
if (status) {
var b = requie('./b');
b.test();
}
});
雖然 AMD也支持CMD寫法,但依賴前置是官方文檔的默認模塊定義寫法。
3、AMD的api默認是一個當多個用,CMD嚴格的區分推崇職責單一。例如:AMD裏require分全局的和局部的。CMD裏面沒有全局的 require,提供 seajs.use()來實現模塊系統的加載啓動。CMD裏每個API都簡單純粹。
部分內容引用《ES6標準入門第三版》以及博客https://blog.csdn.net/u010552788/article/details/51069451