文章目录
  1. 1. 先知先觉
  2. 2. AMD规范
    1. 2.1. define() 函数
    2. 2.2. require() 函数
  3. 3. RequireJS模块的加载(手打RequireJS相关代码地址)
    1. 3.1. 调用require.js
    2. 3.2. 模块加载自定义
    3. 3.3. AMD模块的写法

先知先觉

随着前端项目越来越复杂,使用模块化开发可以提高代码的重用性,并且使项目结构清晰化。一个模块就是实现特定功能的文件,有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块。模块开发需要遵循一定的规范,否则就都乱套了。

目前,通行的js模块规范主要由三种:AMD,CMD,CommonJS.

简单来说,就是使用define定义模块,使用require调用模块。

先盗用一张图来方便理解他们的异同:
module

AMD规范

AMD规范文档
AMDAsynchronous Module Definition,中文名是异步模块定义的意思。它是一个在浏览器端模块化开发的规范,服务器端的规范是CommonJS

模块将被异步加载,模块加载不影响后面语句的运行。所有依赖某些模块的语句均放置在回调函数中。

AMDRequireJS 在推广过程中对模块定义的规范化的产出。

优点:

  1. 实现js文件的异步加载,避免网页失去响应;
  2. 管理模块之间的依赖性,便于代码的编写和维护。

目前,实现AMD的库有RequireJScurlDojoNodules 等。

define() 函数

AMD规范只定义了一个函数 define,它是全局变量。函数的描述为:

1
define(id?, dependencies?, factory);

id:指定义中模块的名字,可选;如果没有提供该参数,模块的名字应该默认为模块加载器请求的指定脚本的名字。如果提供了该参数,模块名必须是“顶级”的和绝对的(不允许相对名字)。

依赖dependencies:是一个当前模块依赖的,已被模块定义的模块标识的数组字面量。
依赖参数是可选的,如果忽略此参数,它应该默认为[“require”, “exports”, “module”]。然而,如果工厂方法的长度属性小于3,加载器会选择以函数的长度属性指定的参数个数调用工厂方法。

工厂方法factory,模块初始化要执行的函数或对象。如果为函数,它应该只被执行一次。如果是对象,此对象应该为模块的输出值。
(来自-segment)

模块名用来唯一标识定义中模块,它们同样在依赖性数组中使用,当一个文件中有多个define定义时,需要使用文件路径作为模块名来区分调用的模块是哪个。

模块名可以为 “相对的” 或 “顶级的”。如果首字符为“.”或“..”则为相对的模块名;如果你定义了根目录(baseUrl),那么顶级的模块名从根命名空间的概念模块解析.

函数定义例子:创建一个名为”alpha”的模块,使用了require,exports,和名为”beta”的模块:

1
2
3
4
5
6
7
define("alpha", ["require", "exports", "beta"], function (require, exports, beta) {
exports.verb = function() {
return beta.verb();
//Or:
return require("beta").verb();
}
});

RequireJS默认假定所有的依赖资源都是js脚本,因此无需在module ID上再加”.js”后缀,RequireJS在进行module ID到path的解析时会自动补上后缀。

require() 函数

可以看下面的实际例子:

1
2
3
require(['jquery','underscore','backbone'],function($, _, Backbone){
console.log($(".box").width());
});

require()函数接受两个参数。第一个参数是一个数组,表示所依赖的模块,上例就是['jquery', 'underscore', 'backbone'],即主模块依赖这三个模块;第二个参数是一个回调函数,当前面指定的模块都加载成功后,它将被调用。加载的模块会以参数形式传入该函数,从而在回调函数内部就可以使用这些模块。require()异步加载jqueryunderscorebackbone,浏览器不会失去响应;它指定的回调函数,只有前面的模块都加载成功后,才会运行,解决了依赖性的问题。

RequireJS模块的加载(手打RequireJS相关代码地址

调用require.js

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

data-main属性的作用是,指定网页程序的主模块。在上例中,就是js目录下面的main.js,这个文件会第一个被require.js加载。由于require.js默认的文件后缀名是js,所以可以把main.js简写成main。

模块加载自定义

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

如果这些模块在其他目录,比如js/lib目录,则有两种写法。一种是逐一指定路径。

1
2
3
4
5
6
7
require.config({
    paths: {
      "jquery": "lib/jquery.min",
      "underscore": "lib/underscore.min",
      "backbone": "lib/backbone.min"
    }
  });

另一种则是直接改变基目录(baseUrl)。

1
2
3
4
5
6
7
8
require.config({
    baseUrl: "js/lib",
    paths: {
      "jquery": "jquery.min",
      "underscore": "underscore.min",
      "backbone": "backbone.min"
    }
  });

注意一点,如果加载require.js模块的时候出现timeout现象,解决办法:只要在config里面加上

1
waitSeconds: 0, //解决timeout问题

除了paths,还有shim用来加载非规范的模块,可以查看相关信息.

AMD模块的写法

require.js加载的模块,采用AMD规范。也就是说,模块必须按照AMD的规定来写。
具体来说,就是模块必须采用特定的define()函数来定义。如果一个模块不依赖其他模块,那么可以直接定义在define()函数之中。
假定现在有一个math.js文件,它定义了一个math模块。那么,math.js就要这样写:

1
2
3
4
5
6
7
8
9
// math.js
  define(function (){
    var add = function (x,y){
      return x+y;
    };
    return {
      add: add
    };
  });

加载方法如下:

1
2
3
4
// main.js
  require(['math'], function (math){
    alert(math.add(1,1));
  });

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

1
2
3
4
//myLib.js
define(['../module/math'],function(math){
return math.add(1,1);
})

当require()函数加载上面这个模块的时候,就会先加载myLib.js文件。

先写到这吧,有点累了,下次接着写。

参考文章:
1.https://github.com/amdjs/amdjs-api/wiki/AMD-(%E4%B8%AD%E6%96%87%E7%89%88)

文章目录
  1. 1. 先知先觉
  2. 2. AMD规范
    1. 2.1. define() 函数
    2. 2.2. require() 函数
  3. 3. RequireJS模块的加载(手打RequireJS相关代码地址)
    1. 3.1. 调用require.js
    2. 3.2. 模块加载自定义
    3. 3.3. AMD模块的写法