本文由雲+社區發表javascript
模塊化是指把一個複雜的系統分解到一個一個的模塊。前端
模塊化開發的優勢:java
(1)代碼複用,讓咱們更方便地進行代碼管理、同時也便於後面代碼的修改和維護。node
(2)一個單獨的文件就是一個模塊,是一個單獨的做用域,只向外暴露特定的變量和函數。這樣能夠避免污染全局變量,減小變量命名衝突。react
js模塊化規範有:CommonJS、AMD、CMD、ES6的模塊系統。本文將依次介紹下每一個規範。jquery
<script type="text/javascript" src="a.js"></script>
<script type="text/javascript" src="b.js"></script>
<script type="text/javascript" src="c.js"></script>
<script type="text/javascript" src="d.js"></script>
複製代碼
缺點:git
(1)加載的時候會中止渲染網頁,引入的js文件越多,網頁失去響應的時間越長;github
(2)會污染全局變量;後端
(3)js文件之間存在依賴關係,加載是有順序的,依賴性最大的要放到最後去加載;當項目規模較大時,依賴關係變得錯綜複雜。瀏覽器
(4)要引入的js文件太多,不美觀,代碼難以管理。
是服務器端模塊的規範,由nodejs推廣使用。該規範的核心思想是:容許模塊經過require方法來同步加載所要依賴的其餘模塊,而後經過 exports 或module.exports 來導出須要暴露的接口。
CommonJS 還能夠細分爲 CommonJS1 和 CommonJS2,區別在於 CommonJS1 只能經過 exports.xx = xx 的方式導出,CommonJS2 在 CommonJS1 的基礎上加入了module.exports = xx 的導出方式。 CommonJS 一般指 CommonJS2。
採用CommonJS 規範導入導出:
// 導出
module.exports = moduleA.someFunc;
// 導入
const moduleA = require('./moduleA');
複製代碼
實例:
//math.js
var num = 0;
function add(a, b) {
return a + b;
}
module.exports = {
//須要向外暴露的變量、函數
num: num,
add: add
}
複製代碼
能夠這樣加載:
//引入自定義的模塊時,參數包含路徑,可省略.js
//引入核心模塊時,不須要帶路徑,如var http = require("http");
var math = require('./math');
math.add(1, 2)//3
複製代碼
實際上,從上面的例子就能夠看出,math.add(1,2)必需要等待math.js加載完成,即require是同步的。
在服務器端,模塊文件保存在本地磁盤,等待時間就是磁盤的讀取時間。但對於瀏覽器而言,因爲模塊都放在服務器端,等待時間取決於網上的快慢。所以更合理的方案是異步加載模塊。
缺點:
(1)不能並行加載模塊,會阻塞瀏覽器加載;
(2)代碼沒法直接運行在瀏覽器環境下,必須經過工具轉換成標準的 ES5;
AMD:異步模塊定義。上面已經介紹過,CommonJS是服務器端模塊的規範,主要是爲了JS在後端的表現制定的,不太適合前端。而AMD就是要爲前端JS的表現制定規範。因爲不是JavaScript原生支持,使用AMD規範進行頁面開發須要用到對應的庫函數,也就是require.js(還有個js庫:curl.js)。實際上AMD 是 require.js在推廣過程當中對模塊定義的規範化的產出。
AMD採用異步方式加載模塊,模塊的加載不影響它後面語句的運行。全部依賴這個模塊的語句,都定義在一個回調函數中,等到加載完成以後,這個回調函數纔會運行。
require.js也採用require()語句加載模塊,可是不一樣於CommonJS:
// 定義一個模塊
define('module', ['dep'], function (dep) {
return exports;
});
// 導入和使用
require(['module'], function (module) {
});
複製代碼
上面示例中的代碼改寫成AMD形式:
math.js定義一個模塊:
define('math', ['jquery'], function (jquery) {//引入jQuery模塊
return {
add: function (x, y) {
return x + y;
}
};
});
複製代碼
導入和使用:
require(['math'], function (math) {
math.add(1, 2)
})
複製代碼
math.add()與加載math模塊不是同步的,不會阻塞瀏覽器的加載。
CMD:通用模塊定義。
國內的玉伯大佬寫了sea.js,實際上CMD就是 sea.js在推廣過程當中對模塊定義的規範化的產出。
define(function (require, exports, module) {
// 模塊代碼
});
複製代碼
說明:
require:能夠把其餘模塊導入進來的一個參數;
exports:能夠把模塊內的一些屬性和方法導出的;
module: 是一個對象,上面存儲了與當前模塊相關聯的一些屬性和方法。
上面示例中的代碼改寫成AMD形式:
define(function (require, exports, module) {
var add = function (a, b) {
return a + b;
}
exports.add = add;
})
//導入和使用
seajs.use(['math.js'], function (math) {
var sum = math.add(1, 2);
});
複製代碼
CMD與AMD的不一樣的在於:
(1)AMD推崇依賴前置;CMD推崇依賴就近,只有在用到某個模塊的時候再去require:
//AMD推崇的依賴關係前置:在定義模塊時就要聲明要依賴的模塊
define(['a', 'b', 'c', 'd'], function (a, b, c, d) { // 依賴必須一開始就寫好
a.doSomething()
// 此處省略100行
...
b.doSomething()
...
})
//CMD推崇依賴就近,按需加載,只有在用到某個模塊時再去require
define(function (require, exports, modules) {
var a = require('a');
a.doSomething();
// 此處省略100行
...
var b = require("b");//按需加載
b.doSomething();
...
})
複製代碼
(2)AMD 的 API 默認是一個當多個用,CMD 的 API 嚴格區分,推崇職責單一。
對於依賴的模塊,AMD是提早執行,CMD是延遲執行。
具體細節可點擊參考
ES6在語言的層面上實現了模塊化。瀏覽器廠商和 Node.js 都宣佈要原生支持該規範。它將逐漸取代 CommonJS 和 AMD 規範,成爲瀏覽器和服務器通用的模塊解決方案。
在 ES6 中,使用export關鍵字來導出模塊,使用import關鍵字引用模塊。可是瀏覽器尚未徹底兼容,須要使用babel轉換成ES5。
// 導出
export function hello() { };
export default {
// ...
};
// 導入
import { readFile } from 'fs';
import React from 'react';
複製代碼
使用import導入模塊時,須要知道要加載的變量名或函數名。
在ES6中還提供了export default,爲模塊指定默認輸出.對應導入模塊import時,不須要使用大括號。
上面示例中的代碼改寫成ES6形式:
//math.js
var num = 0;
var add = function (a, b) {
return a + b;
};
export { num, add };
//導入
import { num, add } from './math';
function test(ele) {
ele.textContent = add(1 + num);
}
複製代碼
缺點
瀏覽器尚未徹底兼容,必須經過工具轉換成標準的 ES5 後才能正常運行。
本文從script引入js文件講起,到服務器端模塊的規範CommonJs,再到推崇依賴前置的瀏覽器端模塊的規範AMD、推崇依賴就近的瀏覽器端模塊的規範CMD,最後介紹了ES6的模塊化。每一個介紹中都有各規範基本的用法和一個示例。若有問題,歡迎指正。
此文已由做者受權騰訊雲+社區發佈