有很长一段时间,我对JS模块化的概念就是处于模糊的状态。感觉自己的智商真的有点低。后来,突然发现模块化其实就是C++中的include
功能,说白了有点像类的封装。茅塞顿开!!!
本文就稍微整理下JS的模块化。
模块化的背景
当项目变得复杂,可能会出现的问题:
- 命名冲突
- 按需加载
依赖管理问题
于是就有了模块的必要性。除了解决以上两个问题之外,模块化还有的好处是:可维护性
- 代码复用
我们来看看目前有哪些解决方案。总的来说,出现了命名空间,模块模式,沙盒,依赖注入,CommonJS,AMD,CMD,UMD,ES6等解决方案。
命名空间(2002)
用对象的方式来模拟命名空间:
netease.add = function(){};
siji.add = function(){};
此方法比较简陋,多人需要约定协调。也仅仅在一定程度上解决了变量冲突的问题。
依赖注入(2004)
写过Angular的人对这个词一定不陌生,自从我有了模块化的概念之后,我对依赖注入的理解就是模块化的一种方式。但确切来说,是引入一个实例化对象。
模块模式(?)
用立即执行函数的方式:
(function($){
var a = 1; // 私有变量
function b(){ //私有方法
// ...
}
return { //暴露给外部的接口
b: b
}
})(jQuery)
但仍没有解决依赖关系,仍然要非常注意脚本的加载顺序。比如上述例子,jQuery必须先加载,不然就会出错。
沙盒(2009)
YUI3的沙盒机制:
YUI().use('node', function(Y){
// Your code goes here.
})
仍然没有解决依赖管理的问题。
CommonJS(2009)
用于服务端的模块处理库,每个文件都是一个模块,Node遵循的就是CommonJS。导入模块的方式:
//a.js
function add(x){
return x+1;
}
module.exports = add;
//b.js
var a = require(a.j);
return a.add(4);
加载文件是同步加载的,在服务器环境是可行的。但不能应用于浏览器。所以就出来了AMD,CMD的解决方案。
AMD(2009)
AMD是Asynchromous Module Definition的缩写,异步模块定义。RequireJS为代表。推崇依赖前置。
//c.js
define(['./a', './b'], function(a, b){
//a, b依赖在一开始就加载好
a.test();
b.test();
})
define(id?, deps?, factory)
define(function(require, exports, module){
//Your code write here
})
require(['./c'], function(c) {
//执行回调函数
});
异步加载,只有当依赖模块加载完毕时,才会执行回调函数。
CMD(2011)
CMD是Common Mudule Definition的缩写。SeaJS为代表。推崇依赖就近。
define(function(require, exports, module){
//需要时候才加载
var a = require('./a');
a.test();
var b = require('./b');
b.test();
})
seajs.use(['./a','./b'],function(a,b){
//执行回调函数
});
UMD(2011)
UMD是Universal Module Definition的缩写,通用模块定义。它是AMD和CommonJS的杂糅,希望能同时处理前后端。主要逻辑为:先判断是否支持Node.js的模块是否存在,存在则使用CommonJS;再判断是否支持AMD(define是否存在),存在则使用AMD加载模块。
(function(root, name, factory){
if (typeof exports === 'object') {
module.exports = factory();
} else if (typeof define === 'function' && define.amd) {
define(factory);
} else {
root[name] = factory();
}
}(this, 'test', function(){
// Your code goes here
})
ES6(2015)
ES6终于引入模块化概念,用简单的import
,export
来处理模块化。不过,ES6尚未被所有浏览器支持,只能通过Babel之类的转译工具来转译。
// a.js
function add(x){
return x+1;
}
export.add = add;
// b.js
import {add} from './a'
export.increase = function(x){
return add(x);
}
小结
既然有了JavaScript正室module,我想以后应该就是module的天下了。JavaScript模块化的问题就得到了完美的解决。当然,目前的方案还是比较简单,以后应该会更加完善。
介绍了模块化的基本概况之后,下一篇我会啃一啃模块化的原理和实现。希望我的智商还够用~~~
参考资料: