1. 模块使用方式
CommonJS :require 引用模块 module.exports 暴露接口
AMD:require 引用模块 使用 define 函数的 return 暴露接口
CMD:require 引用模块 module.exports 或 exports 暴露接口
ES6:import 引用模块 export default 暴露接口
2. 模块加载方式
CommonJS :运行时加载,一个模块就是一个对象,
加载一个模块就是加载这个模块的所有方法,然后读取其中需要的方法。
AMD:并行加载,提前执行。
CMD:并行加载,按需执行。
ES6 :编译时加载,在模块编译时就完成加载,
引用的时候只加载需要的方法,其他方法不加载。
1CommonJS(node.js)
CommonJS是服务器模块的规范,Node.js采用了这个规范。
根据 CommonJS 规范,一个单独的文件就是一个模块,
每一个模块都是一个单独的作用域,
在一个文件定义的变量(还包括函数和类)
,都是私有的,对其他文件是不可见的)
CommonJS规范加载模块是同步的,
也就是说,只有加载完成,才能执行后面的操作
Node.js 主要用于服务器编程,加载的模块文件一般都已经存在本地硬盘,
加载起来较快,不用考虑异步加载的方式,
所以 CommonJS 的同步加载模块规范是比较适用的。
但如果是浏览器环境,要从服务器加载模块,这是就必须采用异步模式。
所以就有了 AMD,CMD 等解决方案。
导出
module.exports = {
x: x,
addX: addX,
};
使用
let math = require('./math.js');
console.log('math.x',math.x);
console.log('math.addX', math.addX(4));
2、AMD(requireJS)
AMD 规范加载模块是异步的,并允许函数回调,
不必等到所有模块都加载完成,后续操作可以正常执行
3、CMD(SeaJS)
通用模块定义
4、AMDvsCMD
二者区别主要表现在模块初始化时机
从规范上来说,AMD 更加简单且严谨,适用性更广,
//AMD
define(['./a','./b'], function (a, b) {
//依赖一开始就写好
a.test();
b.test();
});
//CMD
define(function (requie, exports, module) {
//依赖可以就近书写
var a = require('./a');
a.test();
...
//软依赖
if (status) {
var b = requie('./b');
b.test();
}
});
4、UMD
即通用模块定义。UMD 是AMD 和 CommonJS的糅合。
AMD 模块以浏览器第一的原则发展,异步加载模块。
CommonJS 模块以服务器第一原则发展,选择同步加载。它的模块无需包装(unwrapped modules)。
这迫使人们又想出另一个更通用的模式 UMD(Universal Module Definition),实现跨平台的解决方案。
UMD 先判断是否支持 Node.js 的模块(exports)是否存在,存在则使用 Node.js 模块模式。
再判断是否支持 AMD(define 是否存在),存在则使用 AMD 方式加载模块。
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['b'], factory);
} else if (typeof module === 'object' && module.exports) {
// Node. Does not work with strict CommonJS, but
// only CommonJS-like environments that support module.exports,
// like Node.
module.exports = factory(require('b'));
} else {
// Browser globals (root is window)
root.returnExports = factory(root.b);
}
}(this, function (b) {
//use b in some fashion.
// Just return a value to define the module export.
// This example returns an object, but the module
// can return a function as the exported value.
return {};
}));
5、ES6模块
ES6模块和CommonJS区别
ES6 模块输出的是值的引用,输出接口动态绑定,而 CommonJS 输出的是值的拷贝。
CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
CommonJS 输出值的拷贝
CommonJS 模块输出的是值的拷贝(类比于基本类型和引用类型的赋值操作)。对于基本类型,一旦输出,模块内部的变化影响不到这个值。对于引用类型,效果同引用类型的赋值操作。
ES6 输出值的引用
ES6 模块是动态关联模块中的值,输出的是值得引用。原始值变了,import 加载的值也会跟着变。
CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
这是因为,CommonJS 加载的是一个对象(即 module.exports 属性),该对象只有在脚本运行完才会生成。而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。
ES6 模块是编译时输出接口,因此有如下2个特点
import 命令会被 JS 引擎静态分析,优先于模块内的其他内容执行
export 命令会有变量声明提升的效果
import 优先执行
在文件中的任何位置引入 import 模块都会被提前到文件顶部
import和 export
import 优先执行
在文件中的任何位置引入 import 模块都会被提前到文件顶部
export 命令变量提升效果
由于 import 和 export 是静态执行,所以 import 和 export 具有变量提升效果。
即 import 和 export 命令在模块中的位置并不影响程序的输出。
// a.js
import { foo } from './b';
console.log('a.js');
export const bar = 1;
export const bar2 = () => {
console.log('bar2');
}
export function bar3() {
console.log('bar3');
}
// b.js
export let foo = 1;
import * as a from './a';
console.log(a);
// 执行结果:
// { bar: undefined, bar2: undefined, bar3: [Function: bar3] }
// a.js
a 模块引用了 b 模块,b 模块也引用了 a 模块,
export 声明的变量也是优于模块其它内容的执行的。
但具体对变量赋值需要等到执行到相应代码的时候。
ES6模块和CommonJS相同点
重复引入某个相同的模块时,模块只会执行一次。
CommonJS 模块循环依赖
在 CommonJS 规范中,当遇到 require() 语句时,会执行 require 模块中的代码,
并缓存执行的结果,当下次再次加载时不会重复执行,而是直接取缓存的结果。
正因为此,出现循环依赖时才不会出现无限循环调用的情况。
ES6 模块循环依赖
跟 CommonJS 模块一样,ES6 不会再去执行重复加载的模块,
又由于 ES6 动态输出绑定的特性,能保证 ES6 在任何时候都能获取其它模块当前的最新值。
动态import
不可以
ES6 模块在编译时就会静态分析,优先于模块内的其他内容执行
if(some condition) {
import a from './a';
}else {
import b from './b';
}
// or
import a from (str + 'b');
可以动态
// a.js
const str = './b';
const flag = true;
if(flag) {
import('./b').then(({foo}) => {
console.log(foo);
})
}
import(str).then(({foo}) => {
console.log(foo);
})
// b.js
export const foo = 'foo';
// babel-node a.js
// 执行结果
// foo
// foo
动态的 import() 提供一个基于 Promise 的 API
如果在浏览器端的 import() 的用途就会变得更广泛,比如 按需异步加载模块
webpack中加载3种模块 | 语法
ES6 模块
import MyModule from ‘./MyModule.js’;
CommonJS(Require)
var MyModule = require(‘./MyModule.js’);
AMD
define([‘./MyModule.js’], function (MyModule) {});