网页的结构越来越复杂,可以看做一个简单的APP。如果像以前一样把所有代码放在一个文件中,会出现一些问题:全局变量相互影响JavaScript文件变大,影响加载速度,结构混乱,难以维护。与后端(如Java)相比,可见明显的差距。2009年,RyanDahl创建了node.js项目,使用JavaScript进行服务器编程,标志着“JS模块化编程”的正式诞生。基本原理是模块是一些功能的集合,所以可以把一个大文件分成一些小文件,在每个文件中定义不同的功能,然后在HTML中引入:varmodule1=newObject({_count:0,m1:function(){//...},m2:function(){//...}});这样做的缺点是模块中的所有成员都暴露了!我们知道函数的局部变量是不能从外部访问的,所以我们可以使用立即执行函数来优化:varmodule1=(function(){var_count=0;varm1=function(){//...};varm2=function(){//...};return{m1:m1,m2:m2};})();可以有多种方式来定义模块。如果你能遵循一定的规范,好处会很大:可以互相参考!模块规范定义node.js中的math.js模块如下:functionadd(a,b){returna+b;}exports.add=add;在其他模块中使用时,使用全局require函数加载:varmath=require('math');math.add(2,3);在服务端同步require没问题,但是浏览器在网络环境下就不能这么玩了,于是就有了异步的AMD规范:require(['math'],function(math){//require([module],回调);math.add(2,3);});模块的定义如下(模块可以依赖其他模块):define(function(){//define([module],callback);varadd=function(x,y){returnx+y;};返回{添加:添加};});许多其他资源可以用RequireJS加载(见这里),非常So强大!工作中多用到SeaJS,使用的规范叫CMD,强烈推荐(应该指异步模式):越懒越好!依赖模块的处理方式和AMD的区别在于:AMD是提前执行的(靠前面),CMD是延迟执行的(靠最近)。CMD中定义模块的方式如下:define(function(require,exports,module){vara=require('./a');a.doSomething();varb=require('./b');b.doSomething();});使用方法直接看文档,这里就不赘述了!SeaJS源码分析刚开始接触模块化的时候,觉得这个太简单了吧:在创建script标签的时候设置onload和src!事实上是,但不完全是!下面开始看SeaJS(sea-debug.js)的代码。模块在加载期间可能会经历以下状态:varSTATUS=Module.STATUS={//1-The`module.uri`isbeingfetchedFETCHING:1,//2-ThemetadatahasbeensavedtocachedModsSAVED:2,//3-The`module.dependencies`arebeingloadedLOADING:3,//4-ThemodulearereadytoexecuteLOADED:4,//5-ThemoduleisbeingexecutedEXECUTING:5,//6-`module.exports`isavailableEXECUTED:6,//7-404ERROR:7}内存中使用的模块对象来维护模块information:functionModule(uri,deps){this.uri=urithis.dependencies=deps||[]//依赖模块ID列表this.deps={}//依赖模块Module对象列表this.status=0//状态this._entry=[]//模块加载后需要调用回调的模块}要在页面启动模块系统,需要使用seajs.use方法:seajs.use('./main',function(main){//依赖和回调方法main.init();});加载过程的整体逻辑可以在Module.prototype.load中看到:=mod.resolve()//解析依赖模块的URL地址emit("load",uris)for(vari=0,len=uris.length;i
