JavaScript 模块化发展历程 
MDN 模块化文档:JavaScript 模块 - JavaScript | MDN (mozilla.org)
IIFE 伪模块化标准 
- Immediaitely Invoked Function Expression
 - 自执行函数
(function () {}}() 
html
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<meta http-equiv="X-UA-Compatible" content="ie=edge" />
		<title>Document</title>
	</head>
	<body>
		<h1>IIFE 模块化标准</h1>
		<!--
    IIFE
      + 所有的内容放在一个自执行函数里面
      + 但是外界不能使用
      + 我可以把我向外暴露的内容直接暴露出来
    解决问题:
      1. 依赖不清
        + 直接在自执行函数的参数位置, 能看到依赖了哪些模块
      2. 变量全局污染
        + 你后面的代码该用什么变量用什么
    问题:
      1. 文件顺序不能动
      2. 只能知道我依赖的几个模块, 但是模块在哪一个文件中不好说
  -->
		<script src="./a.js"></script>
		<script src="./b.js"></script>
		<script src="./c.js"></script>
	</body>
</html>a.js
js
// 我作为一个独立模块形式出现
(function () {
	// 所有的内容都在 私有作用域
	var num = 100;
	var flag = true;
	function af1() {
		console.log("a.js 里面的 af1");
	}
	function af2() {
		console.log("a.js 里面的 af2");
	}
	// 把我想向外暴露的内容暴露出去
	// 以一个对象的形式挂载在 window 上
	window.modA = {
		af1: af1,
		af2: af2,
	};
})();b.js
js
// 我作为一个独立模块形式出现
(function (modA) {
	// 所有的内容都在 私有作用域
	var num = 200;
	var flag = false;
	function bf1() {
		console.log("b.js 里面的 bf1");
	}
	function bf2() {
		console.log("b.js 里面的 bf2");
	}
	window.modB = {
		bf1,
	};
})(modA);c.js
js
// 我还是做整合的模块
(function (modA, modB) {
	modA.af1();
})(modA, modB);CommonJs 模块化标准 
- 2009 年,nodejs 出现了
 - 使用 JS 去做服务端语言
 - 伴生的是 commonJs 模块化标准
 - 缺点: 只能在后端 JS 里面用
 
html
AMD 模块化标准(requirejs 标准) - Async Module Definition 
- 官网:RequireJS
 - 说明:amdjs-api/AMD.md at master · amdjs/amdjs-api (github.com)
 - 2011 年由社区发起的
 - 因为非官方,没有关键字,大家书写了一套叫做 require.js 的第三方文件来实现标准化规范
 - 把每一个 JS 独立出来 
- 使用了导入导出的语法来实现模块化
 - 在 jS 文件里面引入另一个 S 文件
 
 - 定义模块 
- 调用 define 的方法
 - 1.独立模块定义:a.js 
- 每一个模块文件开始执行 define()
 - 不依赖其他文件,就是一个单纯的模块
 - 向外暴露的内容,直接 return 出去就好了
 
 - 2.依赖其他模块的模块:b.js 
- 也是一个模块文件,但是依赖其他模块的内容
 - 使用 define() 定义
 - 语法: 
define([ 依赖文件1, 依赖文件2, ... ], function (模块A, 模块B, ...) {}) 
 - 3.导入其他模块:c.js 
- 一个模块整合文件
 - 直接使用 a.js 文件里面的方法
 - 使用这个方法 require()
 - 语法: 
require([ 依赖文件1, 依赖文件2, ... ], function (模块1, 模块2) {}) 
 
 
html
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<meta http-equiv="X-UA-Compatible" content="ie=edge" />
		<title>Document</title>
		<script src="../modules/require.js"></script>
	</head>
	<body>
		<h1>AMD 模块化标准 - 依赖前置</h1>
		<h2>页面必须引入一个叫做 require.js 的文件</h2>
		<p>在官网下载:https://requirejs.org/docs/download.html</p>
		<!--
    页面只需要引入最后的整合文件就可以了
    解决问题:
      1. 依赖很清晰
        + 因为只有一个文件, 那么所有的东西都在一个文件里面出现
      2. 变量全局污染
        + 没有全局污染, 都在私有作用域
    问题:
      1. 依赖前置
        + 不管多少行以后使用的东西, 都会在打开页面的时候就加再进来
        + 缺点: 首屏加载时间长
        + 优点: 后期操作流畅
  -->
		<script src="./c.js"></script>
	</body>
</html>a.js
js
define(function () {
	// 我是 modA 模块
	var num = 100;
	var flag = true;
	// 我自己文件里面的代码执行
	console.log("a.js 里面的代码执行");
	for (var i = 0; i < 10000; i++) {
		console.log(1);
	}
	// 定义一些方法
	function af1() {
		console.log("a.js 里面的 af1");
	}
	function af2() {
		console.log("a.js 里面的 af2");
	}
	// 向外暴露的内容
	return {
		af1,
		af2,
	};
});b.js
js
// 我是一个模块 B, 我需要依赖一些 a.js 文件里面的内容
define(["./a.js"], function (modA) {
	console.group("b.js 文件里面的打印");
	console.log("我依赖了 a.js 文件里面的内容", modA);
	console.groupEnd();
	return {
		bf1() {
			console.log("我是 b.js 文件里面的 bf1 方法");
		},
	};
});c.js
js
require(["./b.js", "./a.js"], function (modB, modA) {
	// modA 就是 a.js 文件后面的 return
	console.group("c.js 文件里面的打印");
	console.log("我依赖的 modA 模块", modA);
	modA.af1();
	modA.af2();
	console.log("我依赖的 modB 模块", modB);
	console.groupEnd();
});CMD - Common Module Defineion - 通用模块定义 
官网:SeaJS - A Module Loader for the Web (zhangxinxu.com)
GitHub:seajs/seajs: A Module Loader for the Web (github.com)
2011 左右, 社区里面出现的一个标准
淘宝 "玉伯", 开发一了个 CMD 的模块化标准
依赖于一个叫做 sea.js 的文件来实现的模块化标准
使用: 文件需要引入一个 sea.js 的文件
1.独立模块定义:a.js
- define(function (require, exports, module) { })
 - require() 用来导入其他文件的
 - module.exports 是为了本文件导出内容的
 - exports 是 module.exports 的别名
 - var exports = module.exports
 
2.依赖其他模块的模块:b.js
你需要依赖其他文件模块
在 define( function (require, exports, module) {
 在你需要的位置使用 require() 方法来导入
 var modA = require('地址')
3.资源整合:c.js
- 使用 seajs.use()
 - 语法: seajs.use(['你要依赖的模块'], function (模块 A) {})
 
html<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>Document</title> <script src="../modules/sea.js"></script> </head> <body> <h1>CMD 模块化标准 - 即时依赖</h1> <h2>需要在页面引入一个叫做 sea.js 的文件</h2> <!-- CMD 解决问题 1. 依赖前置 + 按需加载, 在你需要的时候, 在加载 + 也留下了依赖前置的 接口 问题: 1. 即时依赖 + 首屏加载快 + 操作不够流畅 --> <script src="./c.js"></script> </body> </html>a.js
jsdefine(function (require, exports, module) { // 我是一个 modA 独立模块 var num = 100; var flag = true; // 我是 a 文件里面的代码 console.log("我是 a.js 文件里面的打印"); for (var i = 0; i < 10000; i++) { console.log(1); } function af1() { console.log("a.js 里面的 af1 方法"); } function af2() { console.log("a.js 里面的 af2 方法"); } // 向外暴露一些内容 module.exports = { af1, af2, }; });b.js
jsdefine(function (require, exports, module) { // 我是 b.js 文件 console.group("b.js 文件里面的打印"); console.log("我是自己的内容"); var modA = require("./a.js"); console.log("我依赖的 modA 文件, ", modA); console.groupEnd(); });c.js
jsseajs.use(["./b.js"], function (modB) { console.group("我是 c.js 文件里面的打印"); console.log("我前置依赖了 modB", modB); console.groupEnd(); });
ES6 Module 
- 2015 年发布, ES6 语法里面自带了一个模块化标准
 - 但各大浏览器厂商并不买账
 - 2016 年开始,Vue 出现了,人家出现了一个脚手架(开发的大框架直接给你搭建好) => 搭建这个架子的时候, 内置了 ES6 模块化标准
 - 2018 年,各大浏览器厂商开始原生支持 ES6 模块化标准
 - 2018 年中,Chrome 率先原生支持 ES6 模块化
 - 语法: 变成了 JS 的语法,和关键字,不需要任何第三方文件的引入
 - 特点: 页面必须在服务器上打开 
- => live server 插件
 - => 如果你想使用模块化语法,script 标签要加一个属性 type="module"
 
 - 使用: 
- 1.每一个文件都可以作为独立模块, 页都可以作为整合文件
 - 2.导出语法 
- 2-1. export default 导出的内容
 - 2-2. export var num = 200
 
 - 3.导入语法 
- 3-1. 接收 export default 导出 
- import 变量 from '哪一个 JS 文件'
 
 - 3-2. 接收 export 导出的恩日哦那个 
- import { 接收变量 } from '哪一个 JS 文件'
 
 
 - 3-1. 接收 export default 导出 
 
 - 2020 年 
- => ES2020 发布新的标准
 - => 多了一个 按需加载的模块化
 - => 语法:import(你要加载的文件).then(function (res) {})
 
 
index.html
html
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<meta http-equiv="X-UA-Compatible" content="ie=edge" />
		<title>Document</title>
	</head>
	<body>
		<h1>ES6 模块化标准</h1>
		<h2>必须要在服务器上打开</h2>
		<h2>script 标签要有 type="module"</h2>
		<!--
    ES6 模块化标准
    解决问题
      1. 变成关键字, 不需要依赖第三方文件
      2. 每一个文件都可以变成模块文件, 也可以是整合文件
    问题:
      1. 浏览器支持不好
        + 必须要在服务器上打开
        + 一旦项目上线, 肯定是服务器打开
      2. 依赖前置
  -->
		<!-- <script src="./c.js" type="module"></script> -->
		<script src="./d.js" type="module"></script>
	</body>
</html>a.js
js
// 我是一个模块
// 因为这个文件并不会通过 script 标签引入 页面, 所以这些变量不再 window 上
var num = 100;
var flag = true;
function af1() {
	console.log("我是 a.js 里面的 af1 方法");
}
function af2() {
	console.log("我是 a.js 里面的 af2 方法");
}
console.log("a.js");
// 单独导出一个 af1 方法
// 一个文件只能由一个 export default
// export default af1
// 如果你要导出多个, 那么需要以对象或者数组的形式
export default {
	af1,
	af2,
};
export const n = num;b.js
js
// 我是一个 b.js 模块
import modA from "./a.js";
// 我这个模块向外导出了一个 num 变量值是 200
// export 可以写多个
export var num = 200;
export const str = "hello world";
export function bf1() {
	console.log("我是 b.js 文件里面的 bf1 函数");
}c.js
js
// 我是整合文件
// 我需要依赖 a.js 文件里面得内容
// modA 接受的是 a.js 文件里面 export default 后面的一整个内容
import modA from "./a.js";
// 我需要依赖 b.js 文件里面的方法
import { num, str } from "./b.js";
console.log("c.js 文件");
console.log(modA);
console.log(num);
console.log(str);d.js
js
// 我需要依赖 a.js 文件
console.log("d.js");
console.log("d.js");
console.log("d.js");
console.log("d.js");
// 需要的时候在去引入 a.js 文件
import("./a.js").then(function (res) {
	console.log(res);
});