javascript模块化编程

一、模块化的概念

为了解决命名冲突和文件依赖等问题,提出了模块化的概念,即将一个实现特定功能的文件定义为一个模块,我们可以通过模块加载,轻松的使用已经写好的代码。

二、CMD与AMD规范

javascript模块化编程主要有CMD和AMD规范。
CMD:就近加载模块,当需要使用的时候才去加载;
AMD:异步加载模块,依赖前置(需要按顺序把需要用到的模块都加载好),加载好的依赖包都被提前分析好,后面的程序直接使用即可。

1.CommonJs(CMD)通用模块定义:

  • 定义模块:一个单独的文件就是一个模块。每一个模块都是一个单独的作用域,即在该模块内部定义的变量,无法被其他模块访问,除非定义为global对象的属性。
  • 模块输出: 模块只有一个出口,module.exports对象,我们需要把模块希望输出的内容放入该对象中,给其他模块访问。
  • 加载模块: 加载模块使用require()方法,该方法读取一个文件并执行,返回文件内部的module.exports对象。
  • CMD的主要代表是SeaJS

2.AMD异步模块定义:
AMD主要为了解决两个问题:

  • 多个js文件可能有依赖关系,被依赖的文件需要早于依赖它的文件加载到浏览器
  • 加载js文件的时候浏览器会停止页面渲染,加载文件越多,页面失去响应时间越长
  • AMD的代表是RequireJS

三、SeaJS

seaJS遵循CMD模块定义规范,一个模块就是一个文件。
1.加载文件
在加载seajs时,可以通过给<script>便签添加@data-main属性,来指定页面的初始脚本。

<script src="sea.ja" data-main="./main"></script>

./为相对路径,“./main”在seajs中被称作模块ID(后面会讲到)

2.SeaJS配置
在SeaJS中使用config()来配置基本的模块信息

seajs.config({
    base: "../url",    //基本路径
    alise: {"jquery": "jquery/jquery.js"}    //给文件起别名
});
``

3.模块定义
语法:define("moduleNmae"?,function(require,exports,module) {
    ...
})`;

moduleName是模块的名称,可以不给定,为了模块的可移植性,一般不给定;
require是一个方法,接受模块标志作为唯一参数,用来获取其他模块提供的接口;
exports是一个对象,用来向外提供模块的接口;
module是一个对象,存储了与当前模块相关的一些属性和方法。

4.模块启动
在SeaJS中,使用seajs.use()来启动已经定义好的模块。
语法:seajs.use(uel,callback);
url:调用模块的地址,url默认的根目录是SeaJS所有的文件夹。填入url后,SeaJS会异步加载url指定的文件,加载完成后执行callback函数,这样就实现了按需加载模块的目的。(callback函数时exports对象)

seajs.use(['./module1','module2'],function(module1,module2) {
   module1.init();
   module2.init();
})

5.模块标识
模块标识分为相对标识和绝对标识
相对标识:以“.”开头,只出现在模块坏境中(define的factory方法里面),永远相对当前的uri来解析。
顶级标识:不以点(.)或者斜线(/)开始,会相对模块系统的基础路径(即SeaJS的base路径)来解析。

如果使用path/moduleName来指定模块,SeaJS将会使用“base路径+模块ID—+.js”这一规则来拼接模块的实际地址;如果模块ID不以点(.)其实,SeaJS则使用base作为基本路径来拼接模块的实际地址。如果没有配置base路径,则默认当前页的上级目录为base路径。

6.SeaJS书写规范

  • 模块factory构造方法的第一个参数必须命名为require
    define(function(require) {});
  • 不要重命名require函数,或在任何作用域中给require重新赋值;
  • require的参数必须是字符串
    reuqure(“moduleName”);
    原因:由于SeaJS是就近加载模块,在页面使用seajs.use()启用一个模块的时候或者模块内部require()时,无法获取或计算变量的值;

四、requireJS

1.加载require脚本

<script src="require.js" data-main="main.js"></script>

require在加载时会去检查data-main属性的值,并将其设为启动脚本

2.定义模块
requireJs模块的好处是,无需全局地引用其他模块。

  • 如果一个模块仅含有键值对,没有任何以来,则在define()中定义这些键值对即可;
define({
    key1: "value1",
    key2: "value2"
});

+没有任何依赖的函数定义

define(function() {...});
  • 模块存在依赖
define(['module1','module2'],function(module1,module2) {...});

第一个参数是依赖的名称数组;第二个参数是一个函数;
在模块的所有依赖加载完毕后,该函数就会被调用来定义该模块,因此该模块应该返回一个定义了本模块的object;(对模块的返回值类型没有强制一定是一个Object,任何函数的返回值都是允许的)
依赖关系会以参数的形式注入到该函数中,参数列表与依赖关系是一一对应的。

3。模块名

  • 我们可以显示的指定模块的名称,但这使得模块不具备移植性,也就是说,如果你将文件移动到其他目录下,你就必须重新命名。
  • define()中的相对模块名
    为了可以再define()内部使用类似 require(“./relative/moduleName”); 的方式加载模块,并正确解析相对名称,需要将“require”本身作为一个依赖,注入到模块中。
define(['require','./relative/moduleName'],function(require) {
    var module1 = require("./relative/moduleName");
});

或者可以使用为CommonJs所设的更短语法:

define(function(require) {
    var module1 = require("./relative/moduleName");
});

相对路径在一些场景中格外有用。例如:为了以便将代码分享给其他人或者项目,你在某个目录下创建了一些模块你可以访问模块的相邻模块,而无需知道该目录的名称。

6.循环依赖
如果有一个循环依赖(模块one和模块two相互依赖),在这种情况下,当模块two的函数被调用时,它会得到一个undefined的one,这时,two可以再模块已经定义好后,用require()放啊发再获取。(需将require作为依赖注入进去)。

define(['require','one'],function(require,two) {
    //在这里,one为undefined
    return {
        require("one").oneDoSomething();
    }
});
参考文章

RequireJS中文网:http://www.requirejs.cn/
饥人谷前端进阶模块化:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值