commonJS
导出:exports;
导入:require;
示例:
//a.js
exports.foo = function() {
console.log('foo')
}
//b.js
var a = require('./a.js')
a.foo()
CommonJS 缺点
- 只能在服务端(Node.js)使用, 不能在浏览器直接使用
- 模块是同步加载的, 如果加载过慢会阻塞进程
AMD(Asyncchronous Module Definition)
- 专门为浏览器量身定制,兼容IE6+(在node.js中使用适配器也可以用)
- 模块是异步加载的
- 用全局函数define来定义模块,用法为:define(id?, dependencies?, factory)
- 使用全局函数require来引入模块, 用法为: require(dependencies?, callback)
示例:
//a.js
define(function(){
return {
hello: function(){
console.log('hello, a.js')
}
}
})
// main.js
require(['a', 'other'], function(a, other){
a.hello() // hello, a.js
other.foo()
})
AMD缺点
- 预下载, 预解释, 带来额外性能消耗
- 书写复杂
- 回调地狱
CMD(Common Module Definition)
比较
- AMD推崇(但不强制)依赖前置,在定义模块的时候就要用require声明其依赖的
- CMD推崇(但不强制)就近依赖,只有在用到某个模块的时候再去require
- CMD不需要AMD那样的回调写法, 可以像CommonJS一样的同步写法(但加载其实还是异步的)
- AMD模块是提前执行的, 而CMD模块默认是延迟执行的 由于延迟加载, CMD用户体验稍差
ES6 Module – 面向未来的模块标准
ES6 在语言标准的层面上,实现了*模块功能,而且实现得相当简单,完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案*
但是到目前为止, 浏览器对ES6 Module的支持还是相当不完善
ES6 模块的设计思想,是尽量的静态化,使得编译时就能确定模块的依赖关系,从而进行一些优化。CommonJS 和 AMD 模块,都只能在运行时确定依赖
在ES8的stage-3提案中, 出现了动态import即import()方法,它返回一个Promise对象, 允许动态导入模块
定义模块:
//变量, module.js
export var bar = 'bar'
// 函数, module.js
export function foo(){}
// 统一导出&重命名, module.js
var bar = 'bar'
function foo(){}
export { bar as myBar, foo }
// 默认导出, module.js
function foo(){}
export default foo
引用模块:
// 从模块中导入指定对象, 支持重命名, main.js
import { foo, bar as myBar } from './module.js'
// 从模块中导入默认对象(名称可跟原名称不一样)
import myFoo from './module.js'
// 执行模块, 但不导入任何值
import './module.js'
// 整体导入
import * as myModule from './module.js'
浏览器使用: 在入口JS文件加上type="module"就可以在该文件内使用ES6 Module 语法
总结
加载机制 | 缺点 | 评价 | |
---|---|---|---|
CommonJS | 同步加载 | 加载时会阻塞线程,仅适用于后端 | NodeJS首创,具有先导意义 |
AMD | 异步加载, 依赖前置 | 写法冗余,依赖多的时候很痛苦 | 前端残留势力 |
CMD | 异步加载, 依赖后知 | 体验略差,需要配合SPM打包工具,配置复杂 | 被创始人说"已死"的规范 |
UMD | 根据运行环境判断选用合适的方式 | 写法臃肿难看 | 前后端跨平台跨平台的解决方案 |
ESM | 编译时静态确定 | 浏览器支持乏力,需要配合转译或打包工具使用 | 未来前端模块管理的规范 |