Skip to content
On this page

前端模块化就是复杂的文件编程一个一个独立的模块,比如 js 文件等等,分成独立的模 块有利于重用(复用性)和维护(版本迭代),这样会引来模块之间相互依赖的问题,所 以有了 commonJS 规范,AMD,CMD 规范等等,以及用于 js 打包(编译等处理)的工具 webpack

CommonJS

NodeJS 是 CommonJS 规范的实现,webpack 也是以 CommonJS 的形式来书写

浏览器不能兼容,因为 require 是同步的,需要等待的,如果我们去使用同步获取服务器 信息,那么浏览器将会“假死”状态,并且浏览器也没有 module、exports、require、global 这四个 node 变量

CommonJS 定义的模块分为:{模块引用(require)} {模块定义(exports)} {模块标识 (module)},运行时加载

转换工具: Browserify

//foo.js
module.exports = function(x) {
  console.log(x);
};
//main.js
var foo = require("./foo");
foo("Hi");
========================》》》》》》
[
  {
    "id":1,
    "source":"module.exports = function(x) {\n  console.log(x);\n};",
    "deps":{}
  },
  {
    "id":2,
    "source":"var foo = require(\"./foo\");\nfoo(\"Hi\");",
    "deps":{"./foo":1},
    "entry":true
  }
]
browerify 将所有模块放入一个数组,id 属性是模块的编号,source 属性是模块的源码,deps 属性是模块的依赖。

AMD

异步模块定义,就是为了解决 commonjs 同步等待的问题,使用异步加载,不影响后面代码 的执行, AMD 也采用 require()语句加载模块,但是不同于 CommonJS,它要求两个参数:

// math.js
  define(function (){
    var add = function (x,y){
      return x+y;
    };
        var ccc = function (x,y){
      return x+y;
    };
    return {
      add: add,
                    ccc:ccc
    };
});
require(['math'], function (math) {
  math.add(2, 3);
});

注意:如果定义的模块依赖于别的模块,那么第一个参数是一个依赖模块的数组,使用require.js的插件可以不一样写
define(['dep1','dep2'],function(dep1,dep2){...});

RequireJS就是实现了 AMD 规范,比如说在项目中使用 require.js,然后设置主入口 去异步加载别的模块

<script src="js/require.js" data-main="js/main"></script>
假定主模块依赖jquery、underscore和backbone这三个模块,main.js就可以这样写:
require(['jquery', 'underscore', 'backbone'], function ($, _, Backbone){
    // some code here
});
或者
require.config({
    baseUrl: "js/lib",
    paths: {
      "jquery": "jquery.min",
      "underscore": "underscore.min",
      "backbone": "backbone.min"
    }
});

CMD/AMD

通用模块定义 seajs CMD 推崇依赖就近,AMD 推崇依赖前置 ,AMD 主张以来一开始加载 完毕,而 CMD 主张需要用到时才加载

define(function(require, exports, module) {
var a = require('./a')
a.doSomething()
// 此处略去 100 行
var b = require('./b') // 依赖可以就近书写
b.doSomething()
// ...
})

AMD | 速度快 | 会浪费资源 | 预先加载所有的依赖,直到使用的时候才执行

CMD | 只有真正需要才加载依赖 | 性能较差 | 直到使用的时候才定义依赖

CommonJS 和 ES6 模块的区别

  • CommonJS 模块是运行时加载,ES6 Modules 是编译时输出接口
  • CommonJS 输出是值的拷贝;ES6 Modules 输出的是值的引用,被输出模块的内部的改变 会影响引用的改变
  • CommonJs 导入的模块路径可以是一个表达式,因为它使用的是 require()方法;而 ES6 Modules 只能是字符串
  • CommonJS this 指向当前模块,ES6 Modules this 指向 undefined
  • 且 ES6 Modules 中没有这些顶层变量 :arguments、require、module、exports、**filename、**dirname

require

  1. CommonJs 的语法(AMD 规范引入方式),CommonJs 的模块是对象。
  2. 运行时加载整个模块(即模块中所有方法),生成一个对象,再从对象上读取它的方法 (只有运行时才能得到这 个对象,不能在编译时做到静态化),理论上可以用在代码的 任何地方
  3. require 是赋值过程,把 require 的结果(对象,数字,函数等),默认是 export 的 一个对象,赋给某个变量(复制或浅拷贝)

import

  1. es6 的一个语法标准(浏览器不支持,本质是使用 node 中的 babel 将 es6 转码为 es5 再执行,import 会被转码为 require),es6 模块不是对象
  2. 是编译时调用,确定模块的依赖关系,输入变量(es6 模块不是对象,而是通过 export 命令指定输出代码,再通过 import 输入,只加载 import 中导的方法,其他方法不加 载),import 具有提升效果,会提升到模块的头部(编译时执行)
  3. import 是解构过程(需要谁,加载谁) image.png