踏上前端这条道路以来,我一直以为自己就是个娴熟的切图工,每天只需要做着重复的劳动,切图,做网站。然而,技术的发展是日新月异的,切图工早就面临淘汰。随着浏览器功能越来越完善,前端项目越来越大,代码越来越复杂,为了适应这种变化,越来越要求前端开发模块化。

首先介绍一下什么是模块化。模块化是指解决某一个复杂问题,按照一种分类的思维把问题进行系统分解,并处理。譬如将巨大的系统代码,整合优化分割成高内聚低耦合的模块,达到便于管理,维护和开发的目的。

模块化设计,必须实现以下能力:

  1. 定义封装的模块
  2. 定义新模块对其他模块的以来
  3. 对其他模块的引入支持。

介绍其中最主要的两种规范,CMD和AMD。

AMD 与 RequireJS

AMD:Asynchronous Module Definition 异步模块定义 [e'sɪŋkrənəs]

AMD采用require([module],callback);加载模块,require有两个参数,一个是依赖的模块数组,一个是回调函数。目前主要有两个Javascript库实现了AMD规范,require.js和curl.js

require.js主要解决以下两个问题:

(1)实现js文件的异步加载,避免网页失去响应;

(2)管理模块之间的依赖性,便于代码的编写和维护。

require.js使用方法

(1)下载js加载入页面

(2)加载自己的代码    <script src="js/require.js" data-main="js/main"></script>

  1. main.js
  2.  
  3. 1 require(['moduleA','moduleB'],function(moduleA,moduleB){
  4. //code here
  5. });
  1. //假定主模块依赖jquery、underscore和backbone这三个模块,main.js就可以这样写:
  2. require(['jquery', 'underscore', 'backbone'], function ($, _, Backbone){
  3.  
  4. // some code here
  5.  
  6. });

模块的加载

require.config();    config方法可以对模块的加载行为进行自定义。require.config()就写在主模块(main.js)的头部。参数就是一个对象,这个对象的paths属性指定各个模块的加载路径,baseUrl为基目录

  1. //main.js
  2. require.config({
  3.  
  4. baseUrl:"js/lib",
  5.  
  6. paths:{
  7.  
  8. "jquery":"jquery.min",
  9.  
  10. "underscore":"underscore".min,
  11.  
  12. "backbone":"backbone.min"
  13.  
  14. }
  15.  
  16. })

AMD模块的写法

模块必须采用特定的define()函数来定义,如果一个模块不依赖于其他模块可以直接定义在define()函数中。

假定一个math模块

  1. // math.js
  2.  
  3. define(function(){
  4.  
  5. var add = function(x,y){
  6.  
  7. return x+y;
  8.  
  9. };
  10.  
  11. return {add:add};
  12.  
  13. });
  14.  
  15. // 加载方法 main.js
  16.  
  17. require(['math'],function(math){
  18.  
  19. alert(math.add(1,1));
  20.  
  21. });

如果这个模块依赖其他模块,define()函数的第一个参数必须是一个数组,指明该模块的依赖性

  1. define(['myLib'],function(myLib){
  2.  
  3. function foo(){
  4.  
  5. myLib.func();
  6.  
  7. }
  8.  
  9. return {foo:foo};
  10.  
  11. });
  12.  
  13. //当require()函数加载上面这个模块的时候,就会先加载myLib.js文件。

 require方法调用模块

  1. require(['module1','module2'],function(module1,module2){
  2.  
  3. module1.func();
  4.  
  5. module2.func();
  6.  
  7. })
  8.  
  9. //在加载 foo 与 bar 两个模块之后执行回调函数实现具体过程。

同时还可以在define定义模块内部进行require调用模块

  1. define( function( require ){
  2. var m1 = require( 'module1' ),
  3. m2 = require( 'module2' );
  4. ...
  5. });

加载非规范的模块

在require()加载之前,先用require.config()方法,定义他们的一些特征。

  1. require.config({
  2.  
  3. shim:{
  4.  
  5. 'underscore':{
  6.  
  7. exports:'_'
  8.  
  9. },
  10.  
  11. 'backbone':{
  12.  
  13. deps:['underscore','jquery'],
  14.  
  15. exports:'Backbone'
  16. }
  17.  
  18. }
  19.  
  20. });
  21.  
  22. /*require.config()接受一个配置对象,这个对象除了有前面说过的paths属性之外,还有一个shim属性,专门用来配置不兼容的模块。具体来说,每个模块要定义
    (1)exports值(输出的变量名),表明这个模块外部调用时的名称;
    (2)deps数组,表明该模块的依赖性。*/
  23.  
  24. //比如jQuery插件定义
  25.  
  26. shim:{
  27.  
  28. 'jquery.scroll':{
  29.  
  30. deps:['jquery'],
  31.  
  32. exports:'jQuery.fn.scroll'
  33. }
  34.  
  35. }

CMD 与 seaJS  (转载)

CMD:Common Module Definition   通用模块加载规范

在CMS中一个模块就是一个文件,格式和AMD有些类似,define(factory);define定义模块,参数factory可以是一个函数或者对象,字符串,当factory为对象字符串时,表示模块的接口是该对象。

定义JSON数据模块:

  1. define({"foo":"bar"});

通用字符串定义模板模块

  1. define('this is {{data}}!');

factory 为函数的时候,表示模块的构造方法,执行构造方法便可以得到模块向外提供的接口。

  1. define( function(require, exports, module) {
  2. // 模块代码
  3. });

define( id?, deps?, factory );

define也可以接受两个以上的参数,字符串id为模块标识,数组deps为模块依赖:

  1. define( 'module', ['module1', 'module2'], function( require, exports, module ){
  2. // 模块代码
  3. });

其与 AMD 规范用法不同。

 require 是 factory 的第一个参数。
  require( id );
  接受模块标识作为唯一的参数,用来获取其他模块提供的接口:
  1. define(function( require, exports ){
  2. var a = require('./a');
  3. a.doSomething();
  4. });

require.async( id, callback? );

require是同步往下执行的,需要的异步加载模块可以使用 require.async 来进行加载:

  1. define( function(require, exports, module) {
  2. require.async('.a', function(a){
  3. a.doSomething();
  4. });
  5. });

exports 是 factory 的第二个参数,用来向外提供模块接口。

  1. define(function( require, exports ){
  2. exports.foo = 'bar'; // 向外提供的属性
  3. exports.do = function(){}; // 向外提供的方法
  4. });

当然也可以使用 return 直接向外提供接口。

  1. define(function( require, exports ){
  2. return{
  3. foo : 'bar', // 向外提供的属性
  4. do : function(){} // 向外提供的方法
  5. }
  6. });

也可以简化为直接对象字面量的形式:

  1. define({
  2. foo : 'bar', // 向外提供的属性
  3. do : function(){} // 向外提供的方法
  4. });

与nodeJS中一样需要注意的是,一下方式是错误的:

  1. define(function( require, exports ){
  2. exports = {
  3. foo : 'bar', // 向外提供的属性
  4. do : function(){} // 向外提供的方法
  5. }
  6. });

需要这么做

  1. define(function( require, exports, module ){
  2. module.exports = {
  3. foo : 'bar', // 向外提供的属性
  4. do : function(){} // 向外提供的方法
  5. }
  6. });

传 入的对象引用可以添加属性,一旦赋值一个新的对象,那么值钱传递进来的对象引用就会失效了。开始之初,exports 是作为 module.exports 的一个引用存在,一切行为只有在这个引用上 factory 才得以正常运行,赋值新的对象后就会断开引用,exports就只是一个新的对象引用,对于factory来说毫无意义,就会出错。

    module 是factory的第三个参数,为一个对象,上面存储了一些与当前模块相关联的属性与方法。
        module.id 为模块的唯一标识。
        module.uri 根据模块系统的路径解析规则得到模块的绝对路径。
        module.dependencies 表示模块的依赖。
        module.exports 当前模块对外提供的接口。

seaJS

    官网 http://seajs.org/docs/
    sea.js 核心特征:
        1. 遵循CMD规范,与NodeJS般的书写模块代码。
        2. 依赖自动加载,配置清晰简洁。
        兼容 Chrome 3+,Firefox 2+,Safari 3.2+,Opera 10+,IE 5.5+。

 seajs.use  用来在页面中加载一个或者多个模块

  1. // 加载一个模块
  2. seajs.use('./a');
  3. // 加载模块,加载完成时执行回调
  4. seajs.use('./a'function(a){
  5. a.doSomething();
  6. });
  7. // 加载多个模块执行回调
  8. seajs.use(['./a','./b'],function(a , b){
  9. a.doSomething();
  10. b.doSomething();
  11. });

AMD 与 CMD 的区别

  下面是玉伯(sea.js创始人)对于 AMD 与 CMD 区别的解释:

    AMD 是 RequireJS 在推广过程中对模块定义的规范化产出。
    CMD 是 SeaJS 在推广过程中对模块定义的规范化产出。
    类似的还有 CommonJS Modules/2.0 规范,是 BravoJS 在推广过程中对模块定义的规范化产出还有不少??
    这些规范的目的都是为了 JavaScript 的模块化开发,特别是在浏览器端的。
    目前这些规范的实现都能达成浏览器端模块化开发的目的。
    区别:
    1. 对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。不过 RequireJS 从 2.0 开始,也改成可以延迟执行(根据写法不同,处理方式不同)。CMD 推崇 as lazy as possible.
    2. CMD 推崇依赖就近,AMD 推崇依赖前置。看代码:
  1. // CMD
  2. define(function(require, exports, module) {
  3. var a = require('./a')
  4. a.doSomething()
  5. // 此处略去 100 行
  6. var b = require('./b') // 依赖可以就近书写
  7. b.doSomething()
  8. // ...
  9. })
  10.  
  11. // AMD 默认推荐的是
  12. define(['./a', './b'], function(a, b) { // 依赖必须一开始就写好
  13. a.doSomething()
  14. // 此处略去 100 行
  15. b.doSomething()
  16. // ...
  17. })
虽然 AMD 也支持 CMD 的写法,同时还支持将 require 作为依赖项传递,但 RequireJS 的作者默认是最喜欢上面的写法,也是官方文档里默认的模块定义写法。

    3. AMD 的
API 默认是一个当多个用,CMD 的 API 严格区分,推崇职责单一。比如 AMD 里,require 分全局 require 和局部
require,都叫 require。CMD 里,没有全局 require,而是根据模块系统的完备性,提供 seajs.use
来实现模块系统的加载启动。CMD 里,每个 API 都简单纯粹。

    4. 还有一些细节差异,具体看这个规范的定义就好,就不多说了。
       
另外,SeaJS 和 RequireJS 的差异,可以参考:https://github.com/seajs/seajs/issues/277
扩展阅读:
前端模块化开发的价值 https://github.com/seajs/seajs/issues/547
前端模块化开发那点历史 https://github.com/seajs/seajs/issues/588
从 CommonJS 到 Sea.js https://github.com/seajs/seajs/issues/269    

RequireJS和AMD规范  http://javascript.ruanyifeng.com/tool/requirejs.html

知乎  AMD 和 CMD 的区别有哪些? http://www.zhihu.com/question/20351507

CMD和AMD探秘的更多相关文章

  1. CMD和AMD区别的概括

    CMD和AMD区别   AMD CMD 关于依赖的模块 提前执行(不过 RequireJS 从 2.0 开始,也改成可以延迟执行(根据写法不同,处理方式不同)), 延迟执行 关于依赖的位置 依赖前置 ...

  2. CMD和AMD

    CMD是国内玉伯在开发SeaJS的时候提出来的,属于CommonJS的一种规范,此外还有AMD,其对于的框架是RequireJS. 二者的异同之处: 二者都是异步(Asynchronuous Modu ...

  3. CommonJS、CMD和AMD规范分别是什么

    CommonJS.CMD和AMD规范分别是什么 Commonjs是用在服务器端的,同步的,如nodejs amd, cmd是用在浏览器端的,异步的,如requirejs和seajs 其中,amd先提出 ...

  4. CMD和AMD的区别

    CMD和AMD俩者之间的区别 AMD和CMD最大的区别是对依赖模块的执行时机处理不同 CMD和AMD都是CommonJS延伸而来的,CommonJS是随着node的出现而出现的,它是一个规范,用于定义 ...

  5. 转: cmd和amd的区别

    AMD 规范在这里:https://github.com/amdjs/amdjs-api/wiki/AMDCMD 规范在这里:https://github.com/seajs/seajs/issues ...

  6. 两句话概括cmd和amd的区别

    === | === | === | ===AMD | 速度快 | 会浪费资源 | 预先加载所有的依赖,直到使用的时候才执行=== | === | === | ===CMD | 只有真正需要才加载依赖 ...

  7. 模块化规范:CMD和AMD的区别

    https://www.zhihu.com/question/20351507/answer/14859415 AMD(异步模块定义) 是 RequireJS 在推广过程中对模块定义的规范化产出.CM ...

  8. CMD与AMD区别

  9. 研究一下javascript的模块规范(CommonJs/AMD/CMD)

    最近写react需要使用nodejs作为开发环境,需要通过npm安装一些第三方的依赖库,因此慢慢感觉到nodejs基础薄弱对我带来了一些不安全感,尤其是javascript模块这一块听到了很多概念,比 ...

随机推荐

  1. ContentProvider官方教程(6)provider支持的数据类型

    Provider Data Types Content providers can offer many different data types. The User Dictionary Provi ...

  2. 使用jquery构建Metro style 返回顶部

    个人一直对metro风格的东西情有独钟,偶然间在腾讯网看到一款小插件,蓝色Metro风格的,所以决定把它放到我的博客中,这样做应该不会有版权问题吧orz.. Complete code 后言 我把他原 ...

  3. js修改浏览器url

    var stateObject = {};var title = "";var newUrl = "/";history.pushState(stateObje ...

  4. Python import 指定目录中的模块

    #coding=utf-8 import os,sys sys.path.append('test') # 下级目录(text) parentdir = os.path.dirname(os.path ...

  5. NPOI大数据分批写入同个Excel

    实现过程: 要导出来的数据库数据量很大,一次取出来压力有点大,故分批取出来,导入到同一个Excel. 因为Excel2003版最大行数是65536行,Excel2007开始的版本最大行数是104857 ...

  6. Codeforces Round #279 (Div. 2) E. Restoring Increasing Sequence 二分

    E. Restoring Increasing Sequence time limit per test 1 second memory limit per test 256 megabytes in ...

  7. VirtualBox全屏切换

    用VirtualBox的时候,如果设置为全屏,想再切换回来,没有什么菜单,只有通过键盘的快捷键来操作,才可以恢复. 我常常忘掉,所以老是得去找,以后需要记住这几个按键的快捷键. 1.全屏与非全屏切换: ...

  8. python中的is、==和cmp()比较字符串

    python 中的is.==和cmp(),比较字符串 经常写 shell 脚本知道,字符串判断可以用 =,!= 数字的判断是 -eq,-ne 等,但是 Python 确不是这样子地.所以作为慢慢要转换 ...

  9. php 怎么设置报错级别 和 控制报错[转]

    在Windows环境下:有时在其他环境下运行正常的程序在自己的环境上会报错误    程序会 报出  Undefined index:   这样的错误例如有如下的代码:                  ...

  10. 一个CSS中Z-index的用法

    一个CSS中Z-index的用法 CSS教程:彻底掌握Z-index属性     大多数的CSS属性都很容易使用.常常,当您对标记语言的元素使用CSS属性时,产生的结果会随着您刷新页面而立即呈现.而另 ...