Web前端模組化方法
前端模組化
1. 模組化優點
目前由於MVVM模式的流行,各種語言都更注重模組化。模組化設計的好處:
- 作用域:避免全域性變數汙染;
- 複用:可重複利用封裝的模組為不同地方實現相同功能;
- 解耦:減少不同功能程式碼相互關聯性,讓程式碼分工明確,也方便Debug;
- 按需載入:加快載入速度、非同步載入不必要的部分;
2. 模組化方法整理
從最早的script標籤開始,前端模組化經過了多種程式設計方案的演化,逐步完善。
2.1 script標籤
<script src="module_a.js"></script> <script src="module_b.js"></script> <script src="main.js"></script>
所有的js檔案共享全域性作用域,容易引起作用域汙染。
2.2 閉包函式(立即執行函式)
(function(){ // xxx })()
這是筆者早年使用最多的js程式設計方式 0_0
雖然避免了作用域汙染的問題,但多個檔案內的函式互相呼叫時,處理較為麻煩。常用方法是:
window.myFunc = function(){}
// 利用閉包函式自定義一個事件監聽觸發機制 // 自定義機制,不會受到預設的事件影響 var EventManager = (function() { var events = {} return { add: function(name, fn) { if(!events[name]){ events[name] = []; } events[name].push(fn); }, fire: function(name, args) { var fnList = events[name]; if(fnList){ for (var i = 0, l = fnList.length; i < l; i++) { var fn = fnList[i]; if (fn && typeof fn == 'function') { fn(args); } } } } } })() // 在閉包內監聽,可呼叫閉包內方法 (function() { EventManager.add('user.login', function(data) { console.log('user.login', data) }) })() // 在任意位置觸發 EventManager.fire('user.login', {name: 'lc'})
自定義事件監聽,相對於window下的函式,更加靈活,也更符合模組化的思想。舉個例子:
通訊系統中,使用者登入後,需要獲取聊天記錄、通訊錄、個人資訊,這些分別在不同的模組(閉包)中。
如果用函式的思想,需要在登入的地方進行不同的方法呼叫,這樣就使得登入模組與多個業務模組產生了耦合;如果用自定義事件的方法,登入後只需要廣播一個事件,同時在多個業務模組分別監聽事件,各模組間就完全沒有耦合,就算任意刪掉一個模組也可以保證其他模組正常執行。
存在問題:
不論是全域性函式、全域性事件、自定義事件,在呼叫每個閉包中的方法時,鬥需要確保該閉包先執行後呼叫。在複雜專案中,需要先執行大量閉包函式,會導致啟動慢、邏輯複雜等各種問題。
2.3 AMD - 非同步模組定義
define('myfunc', ['math'], function(math) { math.sum(1, 2) });
通過define
函式引入需要的依賴包,每個模組所依賴的包/模組一目瞭然。
2.4 CMD - 通用模組定義
define(function(require, exports, module) { const math = require('math') math.sum(1, 2) })
CMD的原則是將引入模組儘量後置,在使用的時候才去引入。
這樣使得js執行時效率更高,更符合lazy load的思維方式,但對程式碼管理確不是很方便。
2.5. CommonJS
const math = require('math') module.exports = function() { math.sum(1, 2) }
目前NodeJS的模組管理常用的就是這種方式,很多NPM的包也是這樣處理的模組引入。
2.6 ES6的模組化
import { myFunc1, myFunc2 } from 'myFuncs'; import Vue from 'vue'; export function hello() {}; export default { // ... };
Vue、React等常用框架目前都在使用這種模組化方法。
比如在vue中,配合vue-router,在元件中按需import模組或模組中的函式,可以通過webpack實現按需載入。同時,這種模組化方式使得模組間的方法呼叫更加方便,不需要考慮模組宣告前後順序,因為webpack會自動生成依賴樹。
2.7 樣式檔案模組化
// util.less .common { color: pink; } // main.less @import 'util.less' .red { color: red; }
樣式檔案目前也支援模組化。
參考:《深入淺出Webpack》