AMD , CMD, CommonJS,ES Module,UMD

JavaScript模块化

规范JavaScript的模块定义和加载机制,下降了学习和使用各类框架的门槛,可以以一种统一的方式去定义和使用模块,提升开发效率,下降了应用维护成本。api

  • 命名冲突
  • 文件依赖

差别

  • AMD 与 CMD:
    • AMD是 RequireJS 在推广过程当中对模块定义的规范化产出。
    • CMD是 SeaJS 在推广过程当中对模块定义的规范化产出。
    • CMD推崇依赖就近,AMD推崇依赖前置。
  • ES Module与CommonJS:
    • CommonJS模块是对象,是运行时加载,运行时才把模块挂载在exports之上(加载整个模块的全部),加载模块其实就是查找对象属性。
    • ES Module不是对象,是使用export显示指定输出,再经过import输入。此法为编译时加载,编译时遇到import就会生成一个只读引用。等到运行时就会根据此引用去被加载的模块取值。因此不会加载模块全部方法,仅取所需。
    • CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
    • CommonJS 模块是运行时加载,ES6 模块是编译时输出接口
  • CommonJS与AMD/CMD:
    • AMD/CMD是CommonJS在浏览器端的解决方案。
    • CommonJS是同步加载(代码在本地,加载时间基本等于硬盘读取时间)。
    • AMD/CMD是异步加载(浏览器必须这么作,代码在服务端)
  • UMD与AMD/CMD
    • UMD(Universal Module Definition)是AMD和CommonJS的糅合,跨平台的解决方案。
    • AMD模块以浏览器第一的原则发展,异步加载模块。
    • CommonJS模块以服务器第一原则发展,选择同步加载,它的模块无需包装(unwrapped modules)。
    • UMD先判断是否支持Node.js的模块(exports)是否存在,存在则使用Node.js模块模式。再判断是否支持AMD(define是否存在),存在则使用AMD方式加载模块。

用法

  • CommonJS
    • 导出使用module.exports,也能够exports。就是在此对象上挂属性。exports指向module.exports,即exports= module.exports
    • 加载模块使用require('xxx')。相对、绝对路径都可。默认引用js,能够不写.js后缀
// commonjs
module.exports.add = function add(params) {
    return ++params;
}
exports.sub = function sub(params) {
    return --params;
}
// index.js
var common = require('./commonjs');
console.log(common.sub(1));
console.log(common.add(1));
复制代码
  • AMD/RequireJS
    • 定义模块:define(id?, dependencies?, factory)
      • 依赖有三个默认的,即"require", "exports", "module"。顺序个数都可视状况
      • 若是忽略则factory默认此三个传入参数
      • id通常是不传的,默认是文件名
    • 加载模块:require([module], factory)
// a.js
define(["b", "require", "exports"], function(b, require, exports) {
    console.log("a.js执行");
    console.log(b);
    // 暴露api可使用exports、module.exports、return
    exports.a = function() {
        return require("b");
    }
})
// b.js
define(function() {
    console.log('b.js执行');
    console.log(require);
    console.log(exports);
    console.log(module);
    return 'b';
})
// index.js
// 支持Modules/Wrappings写法,注意dependencies得是空的,且factory参数不可空
define(function(require, exports, module) {
    console.log('index.js执行');
    var a = require('a');
    var b = require('b');
})
// index.js
require(['a', 'b'], function(a, b) {
    console.log('index.js执行');
})
复制代码
  • CMD/SeaJS
    • 定义模块:define(factory)
      • require, exports, module参数顺序不可乱
      • 暴露api方法可使用exports、module.exports、return
      • 与requirejs不一样的是,如果未暴露,则返回{},requirejs返回undefined
    • 加载模块:require
    • 定义模块无需列依赖,它会调用factory的toString方法对其进行正则匹配以此分析依赖
    • 预先下载,延迟执行
// a.js
define(function(require, exports, module) {
    console.log('a.js执行');
    console.log(require);
    console.log(exports);
    console.log(module);
})
// b.js
define(function(require, module, exports) {
    console.log('b.js执行');
    console.log(require);
    console.log(exports);
    console.log(module);
})
// index.js
define(function(require) {
    var a = require('a');
    var b = require('b');
    console.log(a);
    console.log(b);
})
复制代码
  • ES Module
    • 输出/export
    • 输入/import
    • 输入的模块变量是不可从新赋值的,它只是个可读引用,不过却能够改写属性
// 报错1
export 1;
// 报错2
const m = 1;
export m;

// 接口名与模块内部变量之间,创建了一一对应的关系
// 写法1
export const m = 1;
// 写法2
const m = 1;
export { m };
// 写法3
const m = 1;
export { m as module };
复制代码
// 相似于对象解构
// module.js
export const m = 1;
// index.js
// 注意,这里的m得和被加载的模块输出的接口名对应
import { m } from './module';
// 如果想为输入的变量取名
import { m as m1 }  './module';
// 值得注意的是,import是编译阶段,因此不能动态加载,好比下面写法是错误的。由于'a' + 'b'在运行阶段才能取到值,运行阶段在编译阶段以后
import { 'a' + 'b' } from './module';
// 如果只是想运行被加载的模块,以下
// 值得注意的是,即便加载两次也只是运行一次
import './module';
// 总体加载
import * as module from './module';
复制代码
  • 总结:
区别项 es模块化 commonJS AMD
可用于服务端仍是浏览器 服务端和浏览器 服务端 浏览器
模块依赖关系什么时候肯定(即:什么时候加载模块) 编译时 运行时 运行时
设计思想 尽可能的静态化
模块是否是对象 不是
是否总体加载模块(即加载的全部方法)
是不是动态更新(即经过接口,能够取到模块内部实时的值) 是。es module输出的是值的引用 不是。commonJS模块输出的是值的拷贝,不存在动态更新
模块变量是不是只读的 v是。缘由:ES6 输入的模块变量,只是一个“符号链接”,因此这个变量是只读的,对它进行从新赋值会报错。
  • commonJS模块就是对象,总体加载模块(即加载的全部方法)浏览器

  • ES6 模块不是对象,而是经过export命令显式指定输出的代码,再经过import命令输入。bash

  • export命令规定的是对外的接口,必须与模块内部的变量创建一一对应关系服务器

  • export语句输出的接口,与其对应的值是动态绑定关系,即经过该接口,能够取到模块内部实时app

  • export命令和import命令能够出如今模块的任何位置,只要处于模块顶层就能够。 若是处于块级做用域内,就会报错,这是由于处于条件代码块之中,就无法作静态优化了,违背了ES6模块的设计初衷。框架

  • import命令具备提高效果,会提高到整个模块的头部,首先执行。异步

相关文章
相关标签/搜索