作为一个曾经的后端开发者,当我第一眼看到一些javascript模块化的代码案例时,我就想到了java、c#这些天生的模块化语言。
今天就拿 require.js 来捋一捋这其中的异同。

模块化

一个基本的javascript模块,应该是隐藏私有成员及方法,暴漏外部调用的所需的接口。
常见的写法有:

var module = (function(){
var prop = '';
var tool = function(p){
};
//...
return {
fn: function(){
tool(prop);
}
};
})();

在以上代码中,外部环境无法读取和修改变量prop和方法tool,但是该模块返回了一个公开的对象,并有一个可执行的方法fn

这不就相当于面向对象编程中的封装吗?
在以上代码中使用了闭包来隔离变量作用域,而像java中可以使用publicprivate这样的关键字来定义成员。

require.js入门

刚才通过一段简单的代码理解了模块化的作用,下面来看看require.js是如何定义和调用模块的。

页面加载

<script data-main="main" src="http://cdn.bootcss.com/require.js/2.1.20/require.min.js"></script>

在页面中插入了require.js文件,使用data-main指定主模块或者叫入口模块,我理解为java中的main()方法。
data-main属性可以写模块文件的路径,在require.js中默认的后缀.js可省略。

入口模块

如果我们的页面非常简单的话,在入口模块中可以写我们的js代码。
比如:

console.log('Hello require.js!');

此时刷新页面就会直接在控制台输出Hello require.js!
当然如果是这样的话,也就没必要用require.js了。

正常的写法一般是这样的:

require(['module1', 'module2'], function (module1, module2){
//...
});

第一个参数数组表示依赖的模块名,然后在其后的回调函数中就可以使用这些模块。

加载模块

当然,不可能凭空使用模块,按照常规肯定需要某个地方指定模块加载路径吧。

在主模块头部可作以下配置:

require.config({
paths: {
'module1': 'js/module1',
'module2': 'js/module2'
}
});

如果所有模块都在同一个目录则可以配置baseUrl

require.config({
baseUrl: 'js',
paths: {
'module1': 'module1',
'module2': 'module2'
}
});

也可以直接使用URL配置远程文件链接。

require.config({
paths: {
'jquery': 'http://cdn.bootcss.com/jquery/2.1.4/jquery'
}
});

与java中的导包的作用类似,import xxx.xxx.xxx;

定义模块

目前常见的的js模块规范有CMDAMDCommonJS以及兼容性写法的UMD,require.js是实现了AMD规范的js库。

定义一个模块tool,如下写法:

define(function (){
var msg = 'The Hello at tool.';
return {
hello: function(){
console.log(msg);
}
};
});

如果该模块依赖其他模块,如jquery,就需要定义模块依赖。如入口模块的定义一样,第一个参数写成模块名数组。

define('[jquery]', function ($){
var msg = 'The Hello at tool.';
return {
hello: function(){
console.log(msg);
console.log($ === undefined);
}
};
});

依赖的模块依然需要在入口模块中配置加载路径,但不是必须要在入口模块中注入。

在这个模块中我们发现了这段代码与一开始的基本模块写法类似,一样是只暴漏必须的调用接口。

现在可以在入口模块中调用这个模块:

require(['tool'], function (t){
t.hello();
});

如果jquery加载正确的话,控制台会输出:

The Hello at tool.
false

好了,现在可以去更新简历在技能上加上require.js了!

结束

各种模块化规范殊途同归,都是为了解决同样的问题。理解了其中一种,都可以轻松掌握其他规范的写法。
未来我们还有天然支持类和模块的ES6,期待吧?

我一直认为好的开发人员不应该局限于一个技术栈,因为这样会阻碍你对一个问题的全面认知和对新知识的快速领会。