非模块化方式开发的痛苦
(1)命名冲突
起初,我们定义了一个通用功能的JS文件,例如 utils.js(其中有一个 each 函数),谁需要谁调用即可
但随着项目和团队越来越大,就会出现问题
小杨在自己的 a.js 中也定义了一个 each 函数,这时有人同时引用了 utils.js 和 a.js,冲突就出现了,小杨只好把自己的 each函数名改为别的,再通知别人改名了,之后,不同开发人员之间不断出现这类问题
后来,团队决定引入命名空间,对 utils.js 进行改造
var org = {};
org.CoolSite = {};
org.CoolSite.Utils = {};
org.CoolSite.Utils.each = function (arr) {
// 实现代码
};
这时,为了调用一个简单的each函数,就要记住一长串的包名
(2)文件依赖
团队又写了一个工具文件,叫 dialog.js,其中需要使用 utils.js 其中的函数,在文档中明确指出使用 dialog.js时必须要先引入 utils.js
有一个 b.js,使用了 dialog.js,页面中就必须引入多个文件,并且顺序不能错
<script src="util.js"></script>
<script src="dialog.js"></script>
<script src="b.js"></script>
现在就很容易的出现了两个问题
1)开发人员常忘记引用被依赖的文件
2)要使用某个功能时,要引入多个其他文件,最后页面中的引用可能会非常多
模块化开发的好处
现在已经有了多个JS模块化开发规范和相应的具体实现,我们只要选择其中一种,按照约定来开发,就可以完全避免命名冲突和文件依赖的问题
只需关心当前模块本身的功能开发,需要其他模块的支持时,在模块内调用目标模块即可
模块化开发示例
CMD是比较常用的模块化规范,下面就使用CMD方式作为示例
目录结构
|-js
|--|-common
|-------|-utils.js
|--|-a.js
//------utils.js------
define(function(require, exports) {
// 对外提供 each 方法
exports.each = function() {...};
});
//------a.js------
define(function(require, exports) {
// 调用其他模块
var utils = require('common/utils');
utils.each();
// ...
// 对外提供自己的 each 方法
exports.each = function() {...};
});
可以看到,非常简单,CMD规定一个文件就是一个模块,其中有3个重要的关键字:
1)define
定义一个模块
2)require
用来调用其他模块
3)exports
用来暴露自己对外提供的接口