JS 模塊化#
#前端 / JS
Common JS#
- 模塊可以多次加載,只會在第一次加載時運行一次,運行結果就會緩存下來,要再次運行模塊,必須清除緩存
- 同步加載,模塊加載會阻塞後面代碼的執行
- 用於伺服器環境(nodejs)
exports
只是對module.exports
的引用,相當於 Node 為每個模塊提供了一個exports
變數,指向module.exports
,相當於每個模塊頭部都有這麼一行代碼
var exports = module.exports
模塊導出與引用
// common-js-a.js 暴露模塊
// 默認加了一行 var exports = module.exports
exports.a = 'hello world';
// common-js-b.js 引入模塊
const moduleA = require('./common-js-a');
console.log(moduleA.a)
AMD#
- 異步加載
- 瀏覽器環境,依賴前置
// a.js 暴露模塊, module1和module2 是其他前置依賴
define(['module1', 'module2'], function (m1, m2) {
return { a: 'hello world' };
})
// b.js 引入模塊
require(['./a.js'], function (moduleA) {
console.log(moduleA.a)
})
CMD#
- 瀏覽器環境
- 異步加載,就近依賴
// 異步加載 就近依賴
// a.js 導出
define(function(require, exports, module) {
exports.a = 'hello CMD'
})
// b.js 導入
define(function(require, exports, module) {
var moduleA = require('./a.js') // 依賴就近
console.log(moduleA.a)
})
UMD#
兼容 AMD、commonJS、全局引用
同時支持運行在瀏覽器和 Node 環境
(function webpackUniversalModuleDefinition(root, factory) {
// Test Comment
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory(require('lodash'));
// Test Comment
else if(typeof define === 'function' && define.amd)
define(['lodash'], factory);
// Test Comment
else if(typeof exports === 'object')
exports['someLibName'] = factory(require('lodash'));
// Test Comment
else
root['someLibName'] = factory(root['_']);
})(this, function(__WEBPACK_EXTERNAL_MODULE_1__) {
// ...
});
ES6 模塊#
// a.js
export const a = 'hello es6 module'
// b.js
import { a } from './a.js'
- 瀏覽器環境,目前仍需要 babel 編譯為 ES5 代碼
- export 只支持對象形式導出,不支持值的導出,export default 指定默認輸出,本質上是一個叫做 default 的變量
總結#
- CommonJS 的同步加載機制主要用於伺服器端,也就是 Node,但與之相伴的阻塞加載特點並不適用於瀏覽器資源的加載,所以誕生了 AMD、CMD 規範
- AMD 與 CMD 都可以在瀏覽器中異步加載模塊,但實際上這兩種規範的開發成本都比較高
- UMD 同時兼容 AMD、commonJS、全局引用等規範,算是目前打包 JS 庫的主流吧
- ES6 在語言標準的層面上實現了模塊化,使用起來非常舒服,目前算是瀏覽器端的標準方案,再加上現代打包工具的加持,稱霸 Node 服務端也指日可待