目前因为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》