先想一想,为什么模块很重要?

因为有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块。

但是,这样做有一个前提,那就是大家必须以同样的方式编写模块,否则你有你的写法,我有我的写法,岂不是乱了套!考虑到Javascript模块现在还没有官方规范,这一点就更重要了。

目前,比较通行的 JS 模块化规范,有三个:CommonJS/AMD/CMD。下面我们来分别介绍

CommonJS

CommonJS 是作用于服务器端的规范

CommonJS规范不适用于浏览器环境,这是因为CommonJS的同步加载策略,这对服务器端不是一个问题,因为所有的模块都存放在本地硬盘,可以同步加载完成,等待时间就是硬盘的读取时间。但是,对于浏览器,这却是一个大问题,因为模块都放在服务器端,等待时间取决于网速的快慢,可能要等很长时间,浏览器处于”假死”状态。

因此,浏览器端的模块,不能采用”同步加载”(synchronous),只能采用”异步加载”(asynchronous)。这就是AMD规范诞生的背景

2009年,美国程序员Ryan Dahl创造了node.js项目,将javascript语言用于服务器端编程 node.js的模块系统,就是参照CommonJS规范实现的
在CommonJs规范中:

  • 一个文件就是一个模块,拥有单独的作用域;
  • 普通方式定义的变量、函数、对象都属于该模块内;
  • 通过require来加载模块;
  • 通过exports和modul.exports来暴露模块中的内容;
  • 所有代码都运行在模块作用域,不会污染全局作用域;模块可以多次加载,但只会在第一次加载的时候运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果;模块的加载顺序,按照代码的出现顺序是同步加载的;
  • dirname代表当前模块文件所在的文件夹路径,filename代表当前模块文件所在的文件夹路径+文件名
  • require(同步加载)基本功能:读取并执行一个JS文件,然后返回该模块的exports对象,如果没有发现指定模块会报错
  • 模块内的exports:为了方便,node为每个模块提供一个exports变量,其指向module.exports,相当于在模块头部加了这句话:var exports = module.exports,在对外输出时,可以给exports对象添加方法,PS:不能直接赋值(因为这样就切断了exports和module.exports的联系)

AMD

AMD是”Asynchronous Module Definition”的缩写,意思就是”异步模块定义”。它采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。

AMD也采用require()语句加载模块,但是不同于CommonJS,它要求两个参数

1
require([module], callback);

  • 第一个参数[module],是一个数组,里面的成员就是要加载的模块;第二个参数callback,则是加载成功之后的回调函数。
  • 目前,主要有两个Javascript库实现了AMD规范:require.jscurl.js
  • AMD 的使用 以 require.js 为例子:
    • 在 html 中只需要引入一个 js 文件 如:
    • <script src="./node_modules/requirejs/require.js" data-main="main.js"></script>
    • 意思是引入 require.js 并指定主 js 文件为 main.js,在main中再去引用其他的模块
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      //main.js 异步引入add.js 模块
      require(['./libs/add.js'],function(add){
      alert(add.add(12,23));
      });
      alert('dfsf');//由于是异步的,这行代码会先执行
      //add.js(被main.js引入的模块)
      define(function(param){
      function add(n1,n2){
      return n1 + n2;
      }
      return {"add":add};
      });

CMD

  • CMD 是 “Common Module Definition”的缩写,意思就是“通用模块定义”。它与 AMD 有很多相似之处,CMD 支持同步模式和异步模式。目前实行 CMD 的主要是 sea.js

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    //html 文件
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./node_modules/seajs/dist/sea.js"></script>
    <script>seajs.use('./main');</script>
    </head>
    <body>

    </body>
    </html>
    //main.js 中去引用(require)模块
    define(function(require,exports,module){
    //同步模式
    // let obj = require('./libs/add');
    // alert(obj.add(1,9));

    //异步模式,这里add和sub对象和前面的模块一一对应
    require.async(['./libs/add','./libs/substruction'],function(add,sub){
    alert(add.add(1,9));
    alert(sub.sub(19,9));

    });
    alert('weew');//如果为异步模式该行代码会提前执行
    });
    //在add.js中定义(exports)模块
    define(function(require,exports,module){
    function add(n1,n2){
    return n1 + n2;
    }
    exports.add = add;
    });
    //同样的在substruction.js 中定义模块
    define(function(require,exports,module){
    function sub(n1,n2){
    return n1 - n2;
    }
    exports.sub = sub;
    });
  • 在实际的应用中可能 CMD 会用的多一些:有同步和异步模式,可读性很高