目前因爲MVVM模式的流行,各類語言都更注重模塊化。模塊化設計的好處:前端
從最先的script標籤開始,前端模塊化通過了多種編程方案的演化,逐步完善。vue
<script src="module_a.js"></script> <script src="module_b.js"></script> <script src="main.js"></script>
全部的js文件共享全局做用域,容易引發做用域污染。webpack
(function(){ // xxx })()
這是筆者早年使用最多的js編程方式 0_0web
雖然避免了做用域污染的問題,但多個文件內的函數互相調用時,處理較爲麻煩。經常使用方法是:vue-router
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下的函數,更加靈活,也更符合模塊化的思想。舉個例子:
通訊系統中,用戶登陸後,須要獲取聊天記錄、通訊錄、我的信息,這些分別在不一樣的模塊(閉包)中。
若是用函數的思想,須要在登陸的地方進行不一樣的方法調用,這樣就使得登陸模塊與多個業務模塊產生了耦合;若是用自定義事件的方法,登陸後只須要廣播一個事件,同時在多個業務模塊分別監聽事件,各模塊間就徹底沒有耦合,就算任意刪掉一個模塊也能夠保證其餘模塊正常運行。編程
存在問題:閉包
不管是全局函數、全局事件、自定義事件,在調用每一個閉包中的方法時,鬥須要確保該閉包先執行後調用。在複雜項目中,須要先執行大量閉包函數,會致使啓動慢、邏輯複雜等各類問題。框架
define('myfunc', ['math'], function(math) { math.sum(1, 2) });
經過 define
函數引入須要的依賴包,每一個模塊所依賴的包/模塊一目瞭然。less
define(function(require, exports, module) { const math = require('math') math.sum(1, 2) })
CMD的原則是將引入模塊儘可能後置,在使用的時候纔去引入。
這樣使得js執行時效率更高,更符合lazy load的思惟方式,但對代碼管理確不是很方便。異步
const math = require('math') module.exports = function() { math.sum(1, 2) }
目前NodeJS的模塊管理經常使用的就是這種方式,不少NPM的包也是這樣處理的模塊引入。
import { myFunc1, myFunc2 } from 'myFuncs'; import Vue from 'vue'; export function hello() {}; export default { // ... };
Vue、React等經常使用框架目前都在使用這種模塊化方法。
好比在vue中,配合vue-router,在組件中按需import模塊或模塊中的函數,能夠經過webpack實現按需加載。同時,這種模塊化方式使得模塊間的方法調用更加方便,不須要考慮模塊聲明先後順序,由於webpack會自動生成依賴樹。
// util.less .common { color: pink; } // main.less @import 'util.less' .red { color: red; }
樣式文件目前也支持模塊化。
參考:《深刻淺出Webpack》