- 实现:常用 IIFE 实现模块化:匿名函数自调用,将数据和行为封装到一个函数内部,外部依赖通过参数传入
- 常见规范:ES6 模块(esm)、CommonJS、CMD、AMD
删除无用代码的算法,集成在 webpack 和 rollup 等打包工具中
- 通用环境,比如 nodejs,不局限于浏览器
- 每个模块提供一个 module 变量
- 一个文件一个模块
- 可以动态引入,所以不支持树摇
- 特点:语法相对简单,浏览器不直接支持
- 明确基于浏览器
- 基本退出了历史舞台
- RequireJS 是 AMD 的一个实现
- 特点:异步加载、同一个文件定义一个模块
- esm 是 javascript 的标准功能,是语言规范,是官方明确的发展方向,cjs 只是 esm 出来之前的临时解决方案而已
- 相比 cjs 的好处是可以使用 tree shaking,支持静态分析
- 模块脚本自动采用严格模式
- 模块顶层的 this 关键字返回 undefined
- esm 是编译时加载,也就是只有所有 import 的模块都加载完成,才会开始执行,这有利于引擎的静态分析,加载的过程会先于代码的执行,却也导致 import 导入语句不能在函数或者 if 语句中执行。
- es2020 提案引入 import() 函数,用来动态加载模块,并且可以用在函数和 if 语句中
- 模块缓存:同一个模块如果加载多次,只会执行一次
- export 导出的是值引用,当模块内部的值被修改时,esm 可以获取到被修改后的值,cjs 获取不到
- 都属于不同的模块规范,require 属于 CommonJS 规范,import 属于 ES module
- require 支持动态导入,import 不支持
- 它们都是一种模块规范,例如 Node 使用的就是 CommonJS 规范。ES module 则是语言标准上的模块规范 区别:
- CommonJS 模块使用 require() 和 module.exports,ES6 模块使用 import 和 export
- CommonJS 模块输出的是一个值的浅拷贝,ES6 模块输出的是值的引用
- CommonJS 模块是运行时加载,ES6 模块是编译时输出接口,是因为 CommonJS 加载的是一个对象(即 module.exports 属性),该对象只有在脚本运行完才会生成,而 ES6 模块不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成
- CommonJS 模块的 require() 是同步加载模块,ES6 模块的 import 命令是异步加载,有一个独立的模块依赖的解析阶段
- ES6 模块之中,顶层的 this 指向 undefined;CommonJS 模块的顶层 this 指向当前模块
- 通用模块定义规范(Universal Module Definition)
- 可以通过运行时或者编译时让同一个代码模块在使用 CommonJs、CMD 甚至是 AMD 的项目中运行。未来同一个 JavaScript 包运行在浏览器端、服务端甚至是 APP 端都只需要遵守同一个写法就行了
- 是前端实现跨平台技术需求发展下的产物
- 它没有自己专有的规范,是集结了 CommonJs、CMD、AMD 的规范于一身,一个简单实现的例子:
((root, factory) => {
if (typeof define === 'function' && define.amd) {
define(['jquery'], factory);
} else if (typeof exports === 'object') {
var $ = requie('jquery');
module.exports = factory($);
} else {
root.testModule = factory(root.jQuery);
}
})(this, ($) => {
return {
name: '我是一个umd模块',
};
});