由CommonJS组织提出了许多新的JavaScript架构方案和标准,但愿能为前端开发提供统一的指引。AMD规范就是其中比较著名一个,全称是Asynchronous Module Definition,即异步模块加载机制。完整描述了模块的定义,依赖关系,引用关系以及加载机制。该规范已被requireJS,NodeJs,Dojo,JQuery使用,能够看出它具备很大的价值。前端
做为一个规范,只需定义其语法API,而不关心其实现。AMD规范简单到只有一个API,即define函数:
define([module-name?], [array-of-dependencies?], [module-factory-or-object]);
其中:
module-name: 模块标识,能够省略。
array-of-dependencies: 所依赖的模块,能够省略。
module-factory-or-object: 模块的实现,或者一个JavaScript对象。
define函数具备的另一个性质,异步性。当define函数执行时,
1)首先会异步的去调用第二个参数中列出的依赖模块
2)当全部的模块被载入完成以后,若是第三个参数是一个回调函数则执行
3)而后告诉系统模块可用,也就通知了依赖于本身的模块本身已经可用。浏览器
下面代码定义了一个alpha模块,而且依赖于内置的require,exports模块,以及外部的beta模块。能够看到,第三个参数是回调函数,能够直接使用依赖的模块,他们按依赖声明顺序做为参数提供给回调函数。
1)require函数让你可以随时去依赖一个模块,即取得模块的引用,从而即便模块没有做为参数定义,也可以被使用;
2)exports是定义的alpha 模块的实体,在其上定义的任何属性和方法也就是alpha模块的属性和方法。经过exports.verb = ...就是为alpha模块定义了一个verb方法。
3)例子中是简单调用了模块beta的verb方法。架构
define("alpha", ["require", "exports", "beta"], function (require, exports, beta) { exports.verb = function() { return beta.verb(); //或者: return require("beta").verb(); } });
define 方法容许你省略第一个参数,这样就定义了一个匿名模块,这时候模块文件的文件名就是模块标识。
若是这个模块文件放在a.js中,那么a就是模块名。能够在依赖项中用"a"来依赖于这个匿名模块。
好处就是模块是高度可重用,一个匿名模块随便放在一个位置就可使用它,模块名就是它的文件路径。
下面的代码就定义了一个依赖于alpha模块的匿名模块:异步
define(["alpha"], function (alpha) { return { verb: function(){ return alpha.verb() + 2; } }; });
define的前两个参数都是能够省略的。第三个参数有两种状况,一种是一个JavaScript对象,另外一种是一个函数。函数
若是是一个对象,那么它多是一个包含方法具备功能的一个对象;也有多是仅提供数据。后者和JSON-P很是相似,所以AMD也能够认为包含了一个完整的JSON-P实现。模块演变为一个简单的数据对象,这样的数据对象是高度可用的,并且由于是静态对象,它也是CDN友好的,能够提升JSON-P的性能。考虑一个提供中国省市对应关系的JavaScript对象,若是以传统JSON-P的形式提供给客户端,它必须提供一个callback函数名,根据这个函数名动态生成返回数据,这使得标准JSON-P数据必定不是CDN友好的。但若是用AMD,这个数据文件就是以下的形式:工具
define({ provinces: [ {name: '上海',areas: ['浦东新区', '徐汇区']}, {name: '江苏',cities: ['南京', '南通']}
//..... ] });
假设这个文件名为china.js,那么若是某个模块须要这个数据,只须要:性能
define(['china'], function(china){ //在这里使用中国省市数据 });
经过这种方式,这个模块是真正高度可复用的,不管是用远程的,仍是Copy到本地项目,都节约了开发时间和维护时间。ui
若是参数是一个函数,其用途之一是快速开发实现。适用于较小型的应用,你无需提早关注本身须要什么模块,本身给谁用。在函数中,能够随时require本身须要的模块。例如:spa
define(function(){ var p = require('china'); //使用china这个模块 });
即你省略了模块名,以及本身须要依赖的模块。这不意味着你无需依赖于其余模块,而是可让你在须要的时候去require这些模块。define方法在执行的时候,会调用函数的toString方法,并扫描其中的require调用,提早帮助你载入这些模块,载入完成以后再执行。这使得快速开发成为可能。code
须要注意的一点是,Opera不能很好的支持函数的toString方法,所以,在浏览器中它的适用性并非很强。但若是你是经过build工具打包全部的 JavaScript文件,这将不是问题,构建工具会帮助你扫描require并强制载入依赖的模块。