将一个复杂的程序依据一定的规则(规范)封装成几个块(文件), 并进行组合在一起,模块的内部数据/实现是私有的, 只是向外部暴露一些接口(方法)与外部其它模块通信。
1.1 无模块化的原始时代
最开始js只是作为一个脚本语言来使用,做一些简单的表单校验,动画实现等等。
代码都是这样的,直接把代码写进
<script>
if(true) {
...
} else {
...
}
for(var i=0; i< 100; i++){
...
}
document.getElementById('button').onClick = function () {
...
}
</script>
1.2 代码量剧增带来的灾难性问题
后来随着ajax异步请求的出现,前端能做的事情越来越多,代码量飞速增长。
也暴露出了一些问题。
全局变量的灾难
这个非常好理解,就是大家的代码都在一个作用域,不同的人定义的变量可能会重复从而产生覆盖。
//试想彭彭定义了一个变量
name = 'pengpeng';
//后来,丁满后面又定义了
name = 'dingman';
//再后来, 彭彭开始使用他定义的变量
if(name === 'pengpeng'){
...
}
这就杯具了。
依赖关系管理的灾难
<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引入的顺序必须被依赖的放在前面,试想要是有几十个文件,我们都要弄清楚文件依赖关系然后手动,按顺序引入,无疑这是非常痛苦的事情。
1.3 早期的解决方式
(1)闭包
moduleA = function() {
var a,b;
return {
add: function (c){
return a + b + c;
};
}
}()
这样function内部的变量就对全局隐藏了,达到了封装的目的,但是最外层模块名还是暴露在全局,要是模快越来越多,依然会存在模块名冲突的问题。
(2)命名空间
Yahoo的YUI早起的做法
app.tools.moduleA.add = function(c){
return app.tools.moduleA.a + c;
}
毫无疑问以上两种方法都不够优雅。
那么,模块化到底需要解决什么问题提呢?我们先设想一下可能有以下几点
安全的包装一个模块的代码
避免全局污染唯一标识一个模块
优雅的将模块api暴露出去
方便的使用模块
2 服务端模块化
Nodejs出现开创了一个新的纪元,使得我们可以使用javascript写服务器代码,对于服务端而言必然是需要模块化的。
2.1 Nodejs和CommonJS的关系这里要说一下Nodejs和CommonJS的关系。
Nodejs的模块化能一种成熟的姿态出现离不开CommonJS的规范的影响
在服务器端CommonJS能以一种寻常的姿态写进各个公司的项目代码中,离不开Node的优异表现Node并非完全按照规范实现,针对模块规范进行了一定的取舍,同时也增加了少许自身特性
参考文章:前端模块化一——规范详述 - 一只傻汪的文章 - 知乎
https://zhuanlan.zhihu.com/p/41568986