持续补充中…
模块化是为了更高效地复用代码,减少重复代码,提高代码的可读性,可维护性,可复用性。
javascript 中的模块化有多种实现方式,本文主要介绍 CommonJS、AMD、CMD、ES6 模块化以及 UMD(通用模块定义)。
模块化分类
按端分类
- 服务端
CommonJS - 浏览器端
AMD、CMD、ES6 Module
按同步异步分类
- 同步
CommonJS - 异步
AMD、CMD、ES6 Module
按是否可以条件加载分类
- 可以条件加载
CommonJS、AMD、CMD - 不能条件加载
ES6 Module
CommonJS(CJS)
CommonJS 是服务器端模块化的一种实现方式,最初是由 Node.js 团队实现的,它通过 require()和 exports()来实现模块的加载和使用。
特点
- 在服务端使用
- 导出的模块为原始值的复制或深拷贝(重点)
代码
目录结构:
- main.js
- module1.js
- module2.js
1 2 3 4 5 6 7 8
| let name1 = "模块1"; function introduce1() { console.log(`我是${name1}`); }
module.exports = { name1, introduce1 };
|
1 2 3 4 5 6 7 8
| let name2 = "模块2"; function introduce2() { console.log(`我是${name2}`); }
module.exports = { name2, introduce2 };
|
1 2 3 4 5 6 7 8 9
|
const { name1, introduce1 } = require("./module1.js"); console.log(name1); introduce1();
const { name2, introduce2 } = require("./module2.js"); console.log(name2); introduce2();
|
AMD
AMD 是浏览器端模块化的一种实现方式,最早是由 RequireJS 团队实现的,它通过 define()和 require()来实现模块的加载和使用。
RequireJS 官网
特点
- 不能按需加载(和 CMD 相比)
AMD 的依赖只要声明了就会被加载
代码
目录结构:
- index.html
- js
- main.js
- require2.3.6.js
- lib
1 2 3 4 5 6 7 8 9 10 11 12
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <script src="js/require2.3.6.js" data-main="js/main"></script> </body> </html>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| require.config({ baseUrl: "js/lib", });
require(["module1"], function (module1) { console.log(module1.name1); module1.introduce1(); module1.myFriend(); });
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| define(["module2"], function (module2) { let name1 = "模块1"; function introduce1() { console.log(`我是${name1}`); } function myFriend() { console.log(`我是${name1},我的朋友是${module2.name2}`); } return { name1, introduce1, myFriend, }; });
|
1 2 3 4 5 6 7 8 9 10 11
| define(function () { let name2 = "模块2"; function introduce2() { console.log(`我是${name2}`); } return { name2, introduce2, }; });
|
CMD
CMD 是浏览器端模块化的一种实现方式,最早是由 SeaJS 团队实现的,它通过 define()和 require()来实现模块的加载和使用。
SeaJS 官网
特点
- 可以按需加载(和 AMD 相比)
CMD 的依赖仅在需要使用时主动声明才会被加载
代码
目录结构:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head>
<body> <script src="js/sea.js"></script> <script> seajs.config({ base: "./js/lib", });
seajs.use("./js/main"); </script> </body> </html>
|
1 2 3 4 5 6 7
| define(function (require, exports, module) { let module1 = require("module1"); console.log(module1.name1); module1.introduce1(); module1.myFriend(); });
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| define(function (require, exports, module) { let name1 = "模块1"; function introduce1() { console.log(`我是${name1}`); } var module2 = require("module2"); function myFriend() { console.log(`我是${name1},我的朋友是${module2.name2}`); } module.exports = { name1, introduce1, myFriend, }; });
|
1 2 3 4 5 6 7 8 9 10 11
| define(function (require, exports, module) { let name2 = "模块2"; function introduce2() { console.log(`我是${name2}`); } module.exports = { name2, introduce2, }; });
|
ES6 Module(ESM)
ES6 Module 是浏览器端模块化的一种实现方式,是在语言层面上的实现的模块化标准,它通过 import 和 export 来实现模块的加载和使用。
特点
- 不能条件加载
ES6 的模块不是对象,import 命令会被 JavaScript 引擎静态分析,在编译时就引入模块代码,而不是在代码运行时加载,所以无法实现条件加载。也正因为这个,使得静态分析成为可能。 - 兼容性问题
目前谷歌浏览器已原生支持 ESM,但是考虑到不同用户的浏览器版本参差不齐,所以兼容性还是要考虑的首要问题 - 需要服务器环境
通过文件协议访问网页不能使用 ESM
代码
目录结构:
- public
- index.html
- main.js
- module1.js
- module2.js
- node_modules
- http-server:因为 ESM 需要部署在服务器,所以使用该第三方库来开启服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head>
<body> <script type="module"> import "./main.js"; </script> </body> </html>
|
1 2 3 4 5 6 7 8 9
| import { name1 as newName, introduce1 } from "./module1.js"; import module2 from "./module2.js";
console.log(newName); introduce1();
console.log(module2.name2); module2.introduce2();
|
1 2 3 4 5 6 7
| export let name1 = "模块1";
export function introduce1() { console.log(`我是${name1}`); }
|
1 2 3 4 5 6 7 8 9 10 11
| let name2 = "模块2"; function introduce2() { console.log(`我是${name2}`); }
export default { name2, introduce2, };
|
UMD
UMD(Universal Module Definition)并非是一个实现模块化的第三方库,
它只是一种用来编写 javascrit 库的通用模式,该模式会自动判断当前环境应该使用什么模块化标准,
比如 JQuery 就使用了 UMD 模式,所以它在 CommonJS、AMD、CMD、ES6 Module 模块化标准中都可以使用
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
(function (root, factory) { if (typeof define === "function" && define.amd) { define(["exports"], factory); } else if (typeof exports === "object") { module.exports = factory(); } else { root.MyModule = factory(); } })(this, function () { var MyModule = {};
MyModule.someFunction = function () { };
return MyModule; });
|
参考