隨着前端的發展,無模塊化存在的問題日益顯露。但在這個過程中,模塊化也是有一定的發展。
stage1-文件划分方式
根據業務或功能封裝某一類變量或者函數;
約定每一個文件都是一個模塊;
當使用到這個模塊的時候,通過script標簽引入到html頁面中,直接使用模塊中的成員(變量|函數);
但當代碼體積達到一定量的時候,這種方法的缺點就很明顯了。
//module-a.js
var name = 'module-a'
function method1 () {
console.log(name + '#method1')
}
function method2 () {
console.log(name + '#method2')
}
//module-b.js
var name = 'module-b'
function method1 () {
console.log(name + '#method1')
}
function method2 () {
console.log(name + '#method2')
}
//index.html
<script src="module-a.js"></script>
<script src="module-b.js"></script>
<script>
// 命名沖突
method1()
// 模塊成員可以被修改
name = 'foo'
</script>
缺點:
- 全部變量都暴露在全局作用域中,沒有私有空間,所有成員都可被外部訪問或者修改
- 當模塊達到一定數量,通過約定的方式很難避免變量沖突
- 無法管理模塊與模塊之間的依賴關系
stage2-命名空間的方式
每個模塊只暴露一個全局對象,所有的成員都掛載到這個全局對象上
//module-a.js
var moduleA = {
name: 'module-a',
method1: function () {
console.log(this.name + '#method1')
},
method2: function () {
console.log(this.name + '#method2')
}
}
//module-b.js
var moduleB = {
name: 'module-b',
method1: function () {
console.log(this.name + '#method1')
},
method2: function () {
console.log(this.name + '#method2')
}
}
//index.html
<script src="module-a.js"></script>
<script src="module-b.js"></script>
<script>
moduleA.method1()
moduleB.method1()
// 模塊成員可以被修改
moduleA.name = 'foo'
</script>
優點:
通過“命名空間”減小了命名沖突的可能
缺點:
模塊內部的成員依然在外部可以被訪問和修改
模塊之間的依賴關系依然不明確
stage3-通過立即執行函數(IIFE)為模塊提供私有空間
具體做法就是將模塊內的代碼放在一個立即執行函數中
若想把某個成員暴露出去,就把該成員掛載到window中
//module-a.js
;(function () {
var name = 'module-a'
function method1 () {
console.log(name + '#method1')
}
function method2 () {
console.log(name + '#method2')
}
window.moduleA = {
method1: method1,
method2: method2
}
})()
//module-b.js
;(function ($) {
var name = 'module-b'
function method1 () {
console.log(name + '#method1')
}
function method2 () {
console.log(name + '#method2')
}
window.moduleB = {
method1: method1,
method2: method2
}
console.log($('#a').html());
})(jQuery)
//index.html
<script src="module-a.js"></script>
<script src="module-b.js"></script>
<script>
moduleA.method1()
moduleB.method1()
// 模塊私有成員無法訪問
console.log(moduleA.name) // => undefined
</script>
優點:
實現了成員私有化,模塊內的變量外界不能隨意訪問
通過立即執行函數,可以傳遞該模塊所依賴的模塊,使模塊對外部的依賴更加清晰
小結:綜上所述,隨着模塊化的發展,之前所提到的問題也逐一被解決,但還是存在一部分沒有解決的問題。先前所有模塊都是通過script標簽引入的。若我們需要某個模塊時,通過script標簽引入了該模塊,但可能會忘記引入該模塊所依賴的模塊。或者當我們刪除某個模塊時,我們也可能會忘記該模塊所依賴的模塊。
stage4-模塊化規范的出現
1.CommonJS
特點:
1.一個文件就是一個模塊
2.每個模塊都有一個單獨的作用域
3.每個模塊暴露出去的成員都由module.exports導出
4.使用其他模塊的成員時使用require函數導入
CommonJS規范主要引用在Node項目中,該規范加載模塊時同步加載,倘若用在瀏覽器中,會有大量的同步請求導致應用比較慢,但在Node中不會有問題(因為Node是啟動時加載模塊)
2.AMD規范(Asynchronous Module Definition)
代表庫:require.js
特點:
不同於CommonJS的同步加載,該模塊可以異步加載模塊,提高程序在瀏覽器的執行效率
但使用起來相對復雜
3.CMD規范( Common Module Definition )
代表庫:Sea.js
特點:
使用上類似於require.js,寫法類似於CommonJS,算是個重復的輪子
4.ES Modules(ES2015的新語法)
特點:
語言層面推出的新語法,比較完善
滿足在web端開發使用模塊化的需求
綜上所述:目前前端模塊化基本統一成了CommonJS(Node.js)和ES Modules(瀏覽器端開發),我們只需掌握這兩種規范開發即可,后續會對着兩個模塊重點展開討論