模塊化
把復(fù)雜的問題分解成相對(duì)獨(dú)立的模塊,降低程序復(fù)雜性,提高代碼的重用。
- commonJS
- AMD
- CMD
- UMD
- ESM
模塊化的核心
- 獨(dú)立的作用域(一個(gè)文件就是模塊,擁有獨(dú)立的作用域,且導(dǎo)出的模塊都自動(dòng)處于
嚴(yán)格模式下,即'use strict') - 如何導(dǎo)出模塊內(nèi)部數(shù)據(jù)
- 如何導(dǎo)入外部模塊數(shù)據(jù)
導(dǎo)出模塊
// 導(dǎo)出單個(gè)
export let name1,name2, ..., nameN;
export let name1 = ...,name2 = ..., nameN;
export function funName() { ... }
export class className { ... }
// 導(dǎo)出列表
export { name1, name2, ..., nameN };
// 重命令導(dǎo)出
export { variable1 as name1, variable2 as name2, ..., nameN };
// 默認(rèn)導(dǎo)出
export default function(...) {...}
export default expression;
export default function name(...) { ... }
export { name1 as default, ... }
// 模塊重定向?qū)С?export * from ...;
export { name1,name2 } from ...;
export { import1 as name1, import2 as name2 } from ...;
export { default } from ...;
導(dǎo)入模塊
靜態(tài)導(dǎo)入
在瀏覽器,import語句只能在聲明了type="module"的 script 的標(biāo)簽中使用
import defaultExport from "module-name";
import * as name from "module-name";
import { export } from "module-name";
import { export as alias } from "module-name";
import { export1 , export2 } from "module-name";
import { foo , bar } from "module-name/path/to/specific/un-exported/file";
import { export1 , export2 as alias2 , [...] } from "module-name";
import defaultExport, { export [ , [...] ] } from "module-name";
import defaultExport, * as name from "module-name";
import "module-name";
靜態(tài)導(dǎo)入方式不支持延遲加載,
import必須這模塊的最開始
document.onclick = function () {
// import 必須放置在當(dāng)前模塊最開始加載
import m1 from './m1.js'
console.log(m1);
}
動(dòng)態(tài)導(dǎo)入
此外,還有一個(gè)類似函數(shù)的動(dòng)態(tài) import(),它不需要依賴 type="module" 的 script 標(biāo)簽。
關(guān)鍵字 import 可以像調(diào)用函數(shù)一樣來動(dòng)態(tài)的導(dǎo)入模塊。以這種方式調(diào)用,將返回一個(gè) promise。
import('./m.js')
.then(m => {
//...
});
// 也支持 await
let m = await import('./m.js');
通過
import()方法導(dǎo)入返回的數(shù)據(jù)會(huì)被包裝在一個(gè)對(duì)象中,即使是default也是如此
CommonJS
在早起前端對(duì)于模塊化并沒有什么規(guī)范,反而是偏向服務(wù)端的應(yīng)用有更強(qiáng)烈的需求,CommonJS 規(guī)范就是一套偏向服務(wù)端的模塊化規(guī)范,NodeJS 就采用了這個(gè)規(guī)范。
獨(dú)立模塊作用域
一個(gè)文件就是模塊,擁有獨(dú)立的作用域
導(dǎo)出模塊內(nèi)部數(shù)據(jù)
通過 module.exports 或 exports 對(duì)象導(dǎo)出模塊內(nèi)部數(shù)據(jù)
// a.js
let a = 1;
let b = 2;
module.exports = {
x: a,
y: b
}
// or
exports.x = a;
exports.y = b;
導(dǎo)入外部模塊數(shù)據(jù)
通過 require 函數(shù)導(dǎo)入外部模塊數(shù)據(jù)
// b.js
let a = require('./a');
a.x;
a.y;
AMD
因?yàn)?CommonJS 規(guī)范一些特性(基于文件系統(tǒng),同步加載),它并不適用于瀏覽器端,所以另外定義了適用于瀏覽器端的規(guī)范
AMD(Asynchronous Module Definition)
https://github.com/amdjs/amdjs-api/wiki/AMD
瀏覽器并沒有具體實(shí)現(xiàn)該規(guī)范的代碼,我們可以通過一些第三方庫來解決
requireJS
// 1.html
<script data-main="scripts/main" src="https://cdn.bootcss.com/require.js/2.3.6/require.min.js"></script>
獨(dú)立模塊作用域
通過一個(gè) define 方法來定義一個(gè)模塊,并通過該方法的第二個(gè)回調(diào)函數(shù)參數(shù)來產(chǎn)生獨(dú)立作用域
// scripts/Cart.js
define(function() {
// 模塊內(nèi)部代碼
})
導(dǎo)出模塊內(nèi)部數(shù)據(jù)
通過 return 導(dǎo)出模塊內(nèi)部數(shù)據(jù)
// scripts/Cart.js
define(function() {
return class Cart {
add(item) {
console.log(`添加商品:${item}`)
}
}
})
導(dǎo)入外部模塊數(shù)據(jù)
通過前置依賴列表導(dǎo)入外部模塊數(shù)據(jù)
// scripts/main.js
// 定義一個(gè)模塊,并導(dǎo)入 ./Cart 模塊
define(['./Cart'], function(Cart) {
let cart = new Cart()
cart.add({name: 'iphoneXX', price: 1000000})
})
requireJS 的 CommonJS 風(fēng)格
require.js 也支持 CommonJS 風(fēng)格的語法
導(dǎo)出模塊內(nèi)部數(shù)據(jù)
// scripts/Cart.js
define(['require', 'exports', 'module'], function(require, exports, module) {
class Cart {
add(item) {
console.log(`添加商品:${item}`)
}
}
exports.Cart = Cart;
})
// 忽略不需要的依賴導(dǎo)入
define(['exports'], function(exports) {
class Cart {
add(item) {
console.log(`添加商品:${item}`)
}
}
exports.Cart = Cart;
})
// 如果是依賴的導(dǎo)入為:require, exports, module,也可以省略依賴導(dǎo)入聲明
define(function(require, exports, module) {
class Cart {
add(item) {
console.log(`添加商品:${item}`)
}
}
exports.Cart = Cart;
})
導(dǎo)入外部模塊數(shù)據(jù)
// scripts/main.js
define(['./Cart'], function(Cart) {
let cart = new Cart()
cart.add({name: 'iphoneXX', price: 1000000})
})
UMD
嚴(yán)格來說,UMD 并不屬于一套模塊規(guī)范,它主要用來處理 CommonJS、AMD、CMD 的差異兼容,是模塊代碼能在前面不同的模塊環(huán)境下都能正常運(yùn)行
(function (root, factory) {
if (typeof module === "object" && typeof module.exports === "object") {
// Node, CommonJS-like
module.exports = factory(require('jquery'));
}
else if (typeof define === "function" && define.amd) {
// AMD 模塊環(huán)境下
define(['jquery'], factory);
}
}(this, function ($) { // $ 要導(dǎo)入的外部依賴模塊
$('div')
// ...
function b(){}
function c(){}
// 模塊導(dǎo)出數(shù)據(jù)
return {
b: b,
c: c
}
}));