在我们最初写代码的时候,引入JS
文件用script
标签来引入,并且在引入多个JS
文件时,当前文件所依赖的JS
文件必须放在前面。也就存在一个顺序的问题,而且这是由开发者去判断和把控的。而现在前端项目越来越复杂,难免会出现很多很多script
标签引入JS
,这无论对于开发和维护都有着一定的缺点。所以出现了模块化的概念。
模块化的形式有很多中,比如把某个特定功能封装成一个函数,但是存在着一个问题,很有可能会出现命名冲突等问题。针对这种问题,又有了对象的方式来模块化,这种不会出现命名冲突,但是外界却可以改变对象内的成员。又有了下面这种方式:
var obj = (function(){
var name = 'liu';
var job = 'Web developer';
function sayName() {
console.log(name + ' is a ' + job);
}
return {
sayName: sayName
}
})()
这样外界就不会修改没有暴露出来的对象内的变量。
上面这些是前端模块化的基础。目前通用的模块化规范主要有COMMONJS
、AMD
、CMD
等等。
COMMONJS
COMMONJS
主要是用于服务端的模块化规范,可以说NodeJS
是它的最佳实践。看下面一个例子:
//导入一个文件系统模块,返回的是一个对象;
var fs = require('fs');
//调用对象的readFile方法,读文件。
fs.readFile('test.txt', function(data){
console.log(data);
});
上面是一个读文件的操作,主要引入文件系统模块,这个是一个同步的过程。
当然,也可以自定义一个模块实现特定的功能。比如要实现一个Multi模块,可以这样来实现:
//multi.js
function multi(a ,b) {
return a*b;
}
module.exports = {
multi: multi
}
//moduleTest.js
var obj = require('./multi.js');
var res = obj.multi(3, 4);
console.log(res);
结果如下:
AMD
上面的COMMONJS
规范不适合浏览器端的模块化开发,因为COMMONJS
去请求模块是一个同步的过程,如果浏览器用这种规范去开发很可能会出现阻塞情况/假死情况。因此AMD
规范就是为解决这种情况而出现的。
由于不是原生JS
所支持的,所以AMD
规范需要用到RequireJS
库。
AMD的用法如下:
定义模块: define([依赖的模块], function(){ //自定义模块 });
引入模块:require([依赖的模块], function(){ //回调 })
在这里,需要说明的一点是:RequireJS
是依赖前置,先去执行依赖的模块,然后再执行当前模块。
CMD
CMD
典型的就是SeaJS
。SeaJS
与RequireJS
实现上是差不多的,但是还是有一些区别,主要是在定义方式上和模块的执行时机上。
定义模块: define(function( require, exports, module ){ })
可以看到,SeaJS
在定义模块的时候,并不会像RequireJS
那样依赖前置,而是就近依赖的原则,需要的时候再去require
。SeaJS
主要是对模块先加载不执行,等到遇到require
的时候才会去执行模块。
对于RequireJS
和SeaJS
的差异可以看下面这个例子:
//c.js
define(function(require, exports, module){
console.log('c Module');
require('./b.js');
console.log('c module finished');
})
//b.js
define(function(require, exports, module){
console.log('b Module');
require('./a.js');
console.log('b module finished');
})
//a.js
define(function(require, exports, module){
console.log('a Module');
})
//html文件
//requirejs文件部分代码
<script src="require.min.js" data-main="c.js"></script>
//SeaJs文件部分代码
<script src="Sea.js"></script>
<script>seajs.use('./c'); </script>
大家可以猜猜两种执行结果有什么不同,这里就不做验证了。
上面这些就是JS模块化的通用方法总结,当然,ES6中已经有了Module模块化的概念,后面还会再对这个进行整理。