一.CommonJS
1.概念
CommonJS 规范概述了同步声明依赖的模块定义。这个规范主要用于在服务器端实现模块化代码组 织,但也可用于定义在浏览器中使用的模块依赖。CommonJS 模块语法不能在浏览器中直接运行;在浏览器端,模块需要提前编译打包处理。
2.特点
-
所有代码都运行在模块作用域,不会污染全局作用域;
-
模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存;
-
模块加载的顺序,按照其在代码中出现的顺序;
3.基本语法
-
暴露模块:
module.exports = value
或exports.xxx = value
-
引入模块:
require(xxx)
,如果是第三方模块,xxx为模块名;如果是自定义模块,xxx为模块文件路径
// example.js
var x = 5;
var addX = function (value) {
return value + x;
};
module.exports.x = x;
module.exports.addX = addX;
引入:
var example = require('./example.js');//如果参数字符串以“./”开头,则表示加载的是一个位于相对路径
console.log(example.x); // 5
console.log(example.addX(1)); // 6
4.模块的加载机制
CommonJS模块的加载机制是,输入的是被输出的值的拷贝。也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。这点与ES6模块化有重大差异。
// example.js
var x = 5;
var addX = function (value) {
return value + x;
};
module.exports.x = x;
module.exports.addX = addX;
引入:
var example = require('./example.js');//如果参数字符串以“./”开头,则表示加载的是一个位于相对路径
console.log(example.x); // 5
console.log(example.addX(1)); // 6
二. AMD
1.概念
AMD异步模块定义,AMD 模块实现的核心是用函数包装模块定义。这样可以防止声明全局变量,并允许加载器库控制 何时加载模块。包装模块的函数是全局 define 的参数,它是由 AMD 加载器库的实现定义的。
// dataService.js文件
// 定义没有依赖的模块
define(function() {
let msg = 'www.chenghuai.com'
function getMsg() {
return msg.toUpperCase()
}
return { getMsg } // 暴露模块
})
//alerter.js文件
// 定义有依赖的模块
define(['dataService'], function(dataService) {
let name = 'chenghuai'
function showMsg() {
alert(dataService.getMsg() + ', ' + name)
}
// 暴露模块
return { showMsg }
})
// main.js文件
(function() {
require.config({
baseUrl: 'js/', //基本路径 出发点在根目录下
paths: {
//映射: 模块标识名: 路径
alerter: './modules/alerter', //此处不能写成alerter.js,会报错
dataService: './modules/dataService'
}
})
require(['alerter'], function(alerter) {
alerter.showMsg()
})
})()
// index.html文件
<!DOCTYPE html>
<html>
<head>
<title>Modular Demo</title>
</head>
<body>
<!-- 引入require.js并指定js主文件的入口 -->
<script data-main="js/main" src="js/libs/require.js"></script>
</body>
</html>
AMD
也支持
require
和
exports
对象,通过它们可以在
AMD
模块工厂函数内部定义
CommonJS
风格的模块。这样可以像请求模块一样请求它们,但
AMD
加载器会将它们识别为原生
AMD 结构,而不是模块定义:

三. UMD
1.概念
为了统一 CommonJS
和
AMD
生态系统,通用模块定义(
UMD
,
Universal Module Definition
)规范 应运而生。UMD
可用于创建这两个系统都可以使用的模块代码。本质上,
UMD
定义的模块会在启动时 检测要使用哪个模块系统,然后进行适当配置,并把所有逻辑包装在一个立即调用的函数表达式(IIFE
) 中。虽然这种组合并不完美,但在很多场景下足以实现两个生态的共存。
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD。注册为匿名模块
define(['moduleB'], factory);
} else if (typeof module === 'object' && module.exports) {
// Node。不支持严格 CommonJS
// 但可以在 Node 这样支持 module.exports 的
// 类 CommonJS 环境下使用
module.exports = factory(require(' moduleB '));
} else {
// 浏览器全局上下文(root 是 window)
root.returnExports = factory(root. moduleB);
}
}(this, function (moduleB) {
// 以某种方式使用 moduleB
// 将返回值作为模块的导出
// 这个例子返回了一个对象
// 但是模块也可以返回函数作为导出值
return {};
}));
四. ES6 模块
1. 模块标签及定义
ECMAScript 6 模块是作为一整块
JavaScript
代码而存在的。带有
type="module"
属性的
<script> 标签会告诉浏览器相关代码应该作为模块执行,而不是作为传统的脚本执行。模块可以嵌入在网页中, 也可以作为外部文件引入:

与传统脚本不同,所有模块都会像<script defer>
加载的脚本一样按顺序执行。解析到
<script
type="module">
标签后会立即下载模块文件,但执行会延迟到文档解析完成。无论对嵌入的模块代码, 还是引入的外部模块文件,都是这样。<script type="module">
在页面中出现的顺序就是它们执行 的顺序。与<script defer>
一样,修改模块标签的位置,无论是在
<head>
还是在
<body>
中,只会影 响文件什么时候加载,而不会影响模块什么时候加载。
下面演示了嵌入模块代码的执行顺序:

不管它是如何加载的,实际上都只会加载一次,如下面的代码所示:

ECMAScript 6
模块借用了
CommonJS
和
AMD
的很多优秀特性。下面简单列举一些。
优点:
模块代码只在加载后执行。
模块只能加载一次。
模块是单例。
模块可以定义公共接口,其他模块可以基于这个公共接口观察和交互。
模块可以请求加载其他模块。
支持循环依赖。
ES6
模块系统也增加了一些新行为。
ES6
模块默认在严格模式下执行。
ES6
模块不共享全局命名空间。
模块顶级
this
的值是
undefined
(常规脚本中是
window
)。
模块中的
var
声明不会添加到
window
对象。
ES6
模块是异步加载和执行的。
2.模块导出
ES6 模块的公共导出系统与
CommonJS
非常相似。控制模块的哪些部分对外部可见的是
export
关 键字。ES6
模块支持两种导出:命名导出和默认导出。不同的导出方式对应不同的导入方式。

导出时也可以提供别名,别名必须在 export
子句的大括号语法中指定。因此,声明值、导出值和 为导出值提供别名不能在一行完成。在下面的例子中,导入这个模块的外部模块可以使用 myFoo
访问 导出的值:

默认导出
(
default export
)就好像模块与被导出的值是一回事。默认导出使用
default
关键字将一 个值声明为默认导出,每个模块只能有一个默认导出。


3.模块导入
模块可以通过使用 import
关键字使用其他模块导出的值。与
export
类似,
import
必须出现在
模块的顶级:

导入对模块而言是只读的,实际上相当于 const
声明的变量。在使用
*
执行批量导入时,赋值给别 名的命名导出就好像使用 Object.freeze()
冻结过一样。直接修改导出的值是不可能的,但可以修改 导出对象的属性。同样,也不能给导出的集合添加或删除导出的属性。要修改导出的值,必须使用有内 部变量和属性访问权限的导出方法。

命名导出和默认导出的区别也反映在它们的导入上。命名导出可以使用*
批量获取并赋值给保存导 出集合的别名,而无须列出每个标识符:
