模块化发展历程
js一开始并没有模块化的概念,直到ajax被提出,前端能够像后端请求数据,前端逻辑越来越复杂,就出现了许多问题:全局变量,函数名冲突,依赖关系不好处理。
当时使用子执行函数来解决这些问题,比如经典的jquery就使用了匿名自执行函数封装代码,将他们全都挂载到全局变量jquery下边。
CommonJs
CommonJs通过nodeJs发扬光大,每个js文件就是一个模块,每个模块有单独的作用域。模块以module.exports为出口,输出一个对象。使用require方法读取文件,并返回其内部的module.exports对象。
CommonJs的问题在于,他的加载是同步的,这在服务端很正常,但是在充满了异步的浏览器里,就不适用了。为了适应浏览器,社区内部发生了分歧。
AMD
AMD 即Asynchronous Module Definition,中文名是异步模块定义的意思。它是一个在浏览器端模块化开发的规范,由于不是JavaScript原生支持,AMD的作者亲自实现了符合AMD规范的RequireJS。
AMD规范规定用全局函数define来定义模块,用法为define(id, dependencies, factory);其中,id为模块标识,dependencies是一个数组,数组里边是该模块依赖的其他模块,factory则是一个匿名函数,里边是该模块的逻辑。
目前公司使用的就是AMD规范。
例如:
//main.js
require(['a', 'b'], function(a, b){
console.log('main.js执行');
a.hello();
$('#b').click(function(){
b.hello();
});
})
requireJs的问题在于,加在一个模块时,会预先加载该模块的所有依赖模块,但是这些依赖很可能一开始并不用到。同时依赖写起来一长串,也很麻烦。比较好的是AMD保留了commonJs中的require、exprots、module3个功能,可以不把以来都写在dependencies中,而是在需要时使用require引入。
CMD
既然requirejs有上述种种不甚优雅的地方,所以必然会有新东西来完善它,这就是后起之秀seajs,seajs的作者是国内大牛淘宝前端步道者玉伯。seajs全面拥抱Modules/Wrappings规范,不用requirejs那样回调的方式来编写模块。而它也不是完全按照Modules/Wrappings规范,seajs并没有使用declare来定义模块,而是使用和requirejs一样的define,或许作者本人更喜欢这个名字吧。(然而这或多或少又会给人们造成理解上的混淆),用seajs定义模块的写法如下:
//main.js
define(function(require, exports, module){
console.log('main.js执行');
var a = require('a');
a.hello();
$('#b').click(function(){
var b = require('b');
b.hello();
});
});
定义模块时无需罗列依赖数组,在factory函数中需传入形参require,exports,module,然后它会调用factory函数的toString方法,对函数的内容进行正则匹配,通过匹配到的require语句来分析依赖,这样就真正实现了commonjs风格的代码。
AMD与CMD的区别
AMD和CMD最明显的区别就是在模块定义时对依赖的处理不同
AMD推崇依赖前置,在定义模块的时候就要声明其依赖的模块
CMD推崇就近依赖,只有在用到某个模块的时候再去require
这种区别各有优劣,只是语法上的差距,而且requireJS和SeaJS都支持对方的写法
面向未来的ES6模块标准
ES6考虑了模块化,使用import和export,但是目前浏览器还不支持,这个标准也只是个雏形。
作者:
黑马程序员前端与移动开发培训学院首发:
http://web.itheima.com/