目录
为何前端需要模块化
为了彻底弄清楚模块化这个东西,我们要从最开始模块化的起源说起。
模块化的起源
在网页开发的早期,js 制作作为一种脚本语言,做一些简单的表单验证或动画实现等,都是直接把代码写进<script>
标签里,代码量非常少。
<script>
if(true) {
...
} else {
...
}
for(var i=0; i< 100; i++){
...
}
document.getElementById('button').onClick = function () {
...
}
</script>
后来随着 ajax 异步请求的出现,前端能做的事情越来越多,代码量飞速增长。也暴露出了一些问题。
全局变量的灾难
这个非常好理解,就是大家的代码都在一个作用域,不同的人定义的变量可能会重复从而产生覆盖。
//试想小明定义了一个变量
name = '小明';
//后来,小华后面又定义了
name = '小华';
//再后来, 小明开始使用他定义的变量
if (name === '小明') {
...
}
这就杯具了。
依赖关系管理的灾难
<script type="text/javascript" src="a.js"></script>
<script type="text/javascript" src="b.js"></script>
<script type="text/javascript" src="c.js"></script>
如果 c 依赖了 b,b 依赖了 c,则 script 引入的顺序必须被依赖的放在前面,试想要是有几十个文件,我们都要弄清楚文件依赖关系然后手动,按顺序引入,无疑这是非常痛苦的事情。
早期的解决方式
闭包
moduleA = function() {
var a,b;
return {
add: function (c){
return a + b + c;
};
}
}()
这样 function 内部的变量就对全局隐藏了,达到了封装的目的,但是最外层模块名还是暴露在全局,要是模快越来越多,依然会存在模块名冲突的问题。
命名空间
Yahoo 的 YUI 早起的做法:
app.tools.moduleA.add = function(c){
return app.tools.moduleA.a + c;
}
毫无疑问以上两种方法都不够优雅。
那么,模块化到底需要解决什么问题呢?我们先设想一下可能有以下几点:
-
安全的包装一个模块的代码,避免全局污染
-
唯一标识一个模块
-
优雅的将模块 api 暴露出去
-
方便的使用模块
现在前端模块化开发已经有了很多既有的规范,以及对应的实现方案。
常见的模块化规范:
CommonJS、AMD、CMD,也有 ES6 的 Modules。
模块块化有两个核心:导入和导出。
这里简要介绍下 CommonJS。
CommonJS 的导入:
var add = require('./add.js');
var config = require('config.js');
var http = require('http');
CommonJS 的导出:
module.exports.add = function () {
...
}
module.exports = function () {
return ...
}