背景

NodeJS的一套比较简洁 Moudles 规范, 使得在服务器端的模块化变得更加简单。很长一段时间,很多公司或者项目都有自己的一套模块化机制, 却未能形成一套统一的标准, NodeJS的Moudles规范如果运用在浏览器端会存在一些问题,如

  1. 服务器端JS模块文件就在本地,浏览器端则需要通过网络请求
  2. 服务器端可以很容易的实现同步或异步请求模块,浏览器端代价会比较大

采用XHR的方式实现同步请求模块,存在明显的跨域缺陷,而使用script的方式,默认是异步的。 在这样的背景下, CommonJS的Modules/Wrappings、AMD、CMD等规范应时而生。

Modules/Wrappings 规范的约定如下,更多请参考:http://wiki.commonjs.org/wiki/Modules/Wrappings

  1. 使用modules.declare定义模块
  2. declare 只接受一个参数,类型可以是函数也可以是object,参数又称为module factory
  3. 如果factory为function,三个参数分别为require、exports、module,factory使用返回值或exports导出模块API
  4. factory如果是对象类型,则将该对象作为模块输出

A basic wrapped module:

module.declare(function(require, exports, module){
exports.foo = "bar";
});

AMD 规范

AMD:全称为异步模块定义, 是专门为浏览器中JavaScript环境设计的规范. 规范本身非常简单, 概括如下:

define(id?, dependencies?, factory);

  id: 模块名

  dependencies: 依赖的模块,如果缺省,默认为 ["require", "exports", "module"]

  factory: 模块工厂,通过排列组合这种模块定义能满足很多场景的需求

AMD在定义自己的Module规范的同时,也简单兼容了CommonJS的Modules/Wrappings。

匿名模块与具名模块

define(["beta"], function (beta) {
exports.verb = function() {
return beta.verb();
}
}); define('alpha', ["beta"], function (beta) {
exports.verb = function() {
return beta.verb();
}
});

匿名模块也带来一些好处,如减少维护成本,使得模块的源代码与它的标识分离。从而实现在不改变模块代码的情况下移动源码文件的位置等。

Simplified CommonJS wrapping

define(function(require, exports, module){
var query = require("query");
var on = require("on");
...
});

AMD模块加载器将会扫描该工厂函数的require调用,并自动的在运行该工厂方法之前加载他们, 也是和CMD规范的重要区别, 很多人在讨论到AMD、CMD上都会探讨这个问题,有许多争议, 不过这点也正是体现了AMD规范的核心:模块依赖必须在真正执行具体的factory方法前解决。

RequireJS是目前最流行的AMD加载器,从代码中可以看出,为了支持CommonJS Wrapping, define会解析工厂函数的FunctionBody,去掉注释,并将require的模块匹配出来, 加到dependencies数组中。

var commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,
cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g; if (!deps && isFunction(callback)) {
deps = [];
if (callback.length) {
callback
.toString()
.replace(commentRegExp, '')
.replace(cjsRequireRegExp, function (match, dep) {
deps.push(dep);
}); deps = (callback.length === 1 ? ['require'] : ['require', 'exports', 'module']).concat(deps); }
}

由于实际项目中的FunctionBody情况比较复杂,cjsRequireRegExp,这个匹配规则不是很强大,如果在实际项目中发现require有问题的地方, 可以将FunctionBody手动匹配一下这个正则表达式, 看是否有问题。

exports有什么好处?

1、相对使用return输出对象, 由于js语言特性决定,代码依次执行, 当模板存在循环依赖关系时,这种export导出就会特别有用。

2、相对于命名空间导出API,它的好处在于它不会影响全局空间, 而且导出的API所属的对象名称不会和模块代码强耦合。 这也是YUI的模块API导出方式采用命名空间的一点局限。

数据或者独立API模块

对于一些仅仅提供数据或者独立方法的模块,factory格式变为obj就可以了, 如:

define({
camelCase: function(x) {
return string.camelCase('abc ABC');
}
});

AMD Plugin Dependency

一个插件依赖应该被描述为如下格式:

[Plugin Module ID]![resource ID]

目前流行的RequireJS、curl、Dojo等支持AMD的加载器都支持插件, 如加载各种格式的数据,在domReady 完成后在执行操作等。由于“!”被插件语法占用,所以在一般资源请求中,请不要使用带有“!”的URL。 完整的插件清单可以参考http://requirejs.org/docs/download.html#plugins

下面是两个RequireJS使用插入的例子:

define([
'backbone',
'text!templates.html'
], function( Backbone, template ){
// ...
}); require(['domReady!'], function (doc) {
//This function is called once the DOM is ready,
//notice the value for 'domReady!' is the current
//document.
});

如果让自己的模块支持AMD规范

jquery是如何做的?

if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
define("jquery", [], function () { return jQuery; } );
}

需要在加载中设置:

define.amd = {
jQuery: true
}; 

小结

AMD仅仅提供了模块定义的规则,在实际项目使用中还需要考虑一些模块合并、打包方案等。

目前,实现AMD规范的库有RequireJS 、curl 、Dojo 、bdLoad 、JSLocalnet 、Nodules等,也有很多库支持AMD规范,即将自己作为一个模块存在,如MooTools 、jQuery 、qwery 、bonzo、firebug等。 在前端模块化发展如此快的今天,未来应该会有很多库或者模块会支持作为满足AMD、CMD or CommonJS Module规范的模块存在。

随着模块化的发展,高质量的模块会越来越多,为了让大家有统一的规则来使用模块, 模块规范化就显得格外重要。 而不管是哪一种模块规范,未来在浏览器端前端是否也可以像Nodejs一样灵活的去使用满足相同规范,甚至各种不同规范的优秀模块, 这样就不用将代码局限同一种框架中, 或许只是自己瞎想。

 

参考:

http://wiki.commonjs.org/wiki/Modules/1.1.1#Module_Identifiers

https://github.com/amdjs/amdjs-api

https://github.com/requirejs/example-multipage

http://requirejs.org/docs/whyamd.html

AMD规范学习笔记的更多相关文章

  1. PSR规范学习笔记

    PSR已经经历了5次变革,如今PSR4就是最新的标准,但是还是有必要了解下5个版本的内容的,于是去php-fig网站看了下英文原版: 大概看了遍,发现这规范很多的必须很多时候只是建议,但是PHP解析器 ...

  2. 阿里Java编程规范 学习笔记

    @import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/c ...

  3. CMD规范学习笔记——基于SEAJS实现

    CMD(Common Module Definition):该规范明确了模块的书写格式和基本交互规则.通常一个模块就是一个JS文件. 通过define关键字来定义模块,最基本的格式为: define( ...

  4. usb2.0 规范学习笔记

    1.一个USB HOST 最多可以同时支持128 个地址,地址0 作为默认地址,只在设备枚举期间临时使 用,而不能被分配给任何一个设备,因此一个USB HOST 最多可以同时支持127 个地址,如果一 ...

  5. CSS规范—分类方法(NEC规范学习笔记)

    一.CSS文件的分类和引用顺序 Css按照性质和用途,将Css文件分成“公共型样式”.“特殊型样式”.“皮肤型样式”,并以此顺序引用,有需要可以添加版本号 1.公共型样式:包含以下几个部分 标签的重置 ...

  6. GP card规范学习笔记

    9.   APDU命令参考 9.1  总的编码规则 A.生命周期状态的编码 可执行的装载文件 b8 b7 b6 b5 b4 b3 b2 b1 含义 16进制命令  0 0 0 0 0 0 0 1 LO ...

  7. 阿里巴巴JAVA开发规范学习笔记

    一.编程规约 (一)命名规约 1.类名驼峰.领域模型除外VO.BO.DTO.DO统称POJO 4.数组String[] args 8.枚举类 Enum ,其实就是特殊的常量类,构造方法强制私有 ( 二 ...

  8. java虚拟机规范学习笔记之数据类型

    1.1 class文件格式 编译后被Java虚拟机所执行的代码使用了一种平台中立的二进制格式来表示,并且经常以文件的形式来存储,这种格式称为class文件格式.class文件格式中精确的定义了类与接口 ...

  9. 学习笔记:CommonJS规范、AMD规范

    CommonJS规范 http://wiki.jikexueyuan.com/project/webpack-handbook/commonjs.html CommonJS 规范 http://www ...

随机推荐

  1. 漂亮的提示框SweetAlert使用教程

    一.简介 所使用过的弹出框插件,SweetAlert是最好用的.发展至今,已经有两个版本,一个是原版 t4t5/sweetalert , 一个是分支版 limonte/sweetalert2 ,更新相 ...

  2. [js高手之路] 跟GhostWu一起封装一个字符串工具库-扩展trim,trimLeft,trimRight方法(2)

    我们接着上一篇的继续,在上一篇我们完成了工具库的架构,本文扩展字符串去空格的方法, 一共有3个 1,trimLeft: 去除字符串左边的空格 2,trimRight: 去除字符串右边的空格 3,tri ...

  3. windows环境VS2015编译TensorFlow C++程序完全攻略

    本文参考和综合了多篇网络博客文章,加以自己的实践,最终终于在windows环境下,编译出可以用于C++程序调用tensorflow API的程序,并执行成功. 考虑到网络上关于这方面的资料还较少,特总 ...

  4. Redis学习之一VMWare Pro虚拟机安装和Linux系统的安装

    一.引言 设计模式写完了,相当于重新学了一遍,每次学习都会有不同的感受,对设计模式的理解又加深了,理解的更加透彻了.还差一篇关于设计模式的总结的文章了,写完这篇总结性的文章,设计模式的文章就暂时要告一 ...

  5. vue+Element实现静态旅游网站

    页面效果: 1.用vue脚手架:vue-cli,新建一个vue项目. 2.npm run dev后,给小颖了一句提示:Your application is running here:http://l ...

  6. Redis 部署主从哨兵 C#使用,实现自动获取redis缓存 实例2

    资料查找https://www.cnblogs.com/tdws/p/5836122.html https://www.cnblogs.com/lori/p/5794454.html private ...

  7. Python学习九:列表生成式

    列表生成式,是Python内置的一种极其强大的生成list的表达式. 如果要生成一个list [1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9] 可以用 range(1 , 10) ...

  8. 高效开发技巧:为什么你下载Git项目这么慢?

    文章首发于[博客园-陈树义],点击跳转到原文<高效开发技巧:为什么你下载Git项目这么慢?>. 笔者所在公司采用的是 GitLab 进行版本管理,但许多同事下载 Git 项目的路径是这样的 ...

  9. 云服务器 远程mysql 无法连接

    问题:mysql不管是用免安装版的,还是用直接安装的,还是用phpStudy直接发布的mysql服务.都只能用localhost登录,不能用服务器的ip进行远程访问 遇到这个问题.按照网上大家介绍的方 ...

  10. LevelDB的源码阅读(二) Open操作

    在Linux上leveldb的安装和使用中我们写了一个测试代码,内容如下: #include "leveldb/db.h" #include <cassert> #in ...