29. JavaScript模块化
1. 什么是模块化
模块化是一种将代码按照一定规则组织成独立、可复用的单元的方式。模块化可以将一个复杂的系统分解为多个独立的模块,每个模块只关注自己的功能,与其他模块之间的耦合度低,从而提高代码的可维护性、复用性和扩展性。
2. 模块化方案
在 JavaScript
中,由于缺乏官方的模块化标准,因此出现了多种模块化方案,比如 CommonJS
、AMD
、CMD
、ES6 Module
等。这些方案都有自己的特点和适用场景,但它们的共同点都是将代码按照一定的规则封装成一个个独立的模块,通过导入和导出接口来实现模块之间的依赖关系,从而组织代码结构,提高代码的可维护性和复用性。
2.1 CommonJS
CommonJS
是 Node.js
中使用的模块化方案,它定义了 require()
和 module.exports
两个函数,可以通过这两个函数导入和导出模块。例如:
//module.js
const obj = {
name: "Jack",
age: 20,
say: function() {
console.log("My name is " + this.name);
}
}
module.exports = obj
//main.js
const obj = require("./module")
console.log(obj.name);//Jack
obj.say();//My name is Jack
2.2 AMD
AMD(Asynchronous Module Definition)
是一种异步加载模块的方案,它采用异步加载方式,在加载模块时不会阻塞页面渲染。RequireJS
是 AMD
的一个实现。
在 AMD
规范中,一个模块需要通过 define
函数来定义,define
函数接收三个参数:
- 模块 ID:一个可选的字符串,用于指定模块的唯一标识符;
- 依赖列表:一个数组,指定该模块依赖的其他模块;
- 模块定义函数:一个函数,用于定义该模块的行为。
//module1.js 无依赖模块 define("module1", function() { const name = "Jack" return { name} });
//module2.js 依赖module1.js define("module2",["module1"], function(m1) { function fullName() { return m1.name + " Ma" } return { fullName } });
//main.js require.config({ path: { module1: "./module1", module2: "./module2" } }) require(["module1", "module2"], function(m1, m2){ console.log("module1 --- ", m1, " module2 --- ", m2.fullName());//module1 --- {name: 'Jack'} module2 --- Jack Ma })
<!-- index.html 引入requirejs库 --> <script data-main="./main.js" src="./lib/require.js"></script>
2.3 CMD
CMD(Common Module Definition)
是另一种模块化方案,它与AMD
类似,但有一些不同之处。
AMD
是在模块定义时就进行依赖的声明和模块的加载,而 CMD
是在模块执行时才进行依赖的声明和模块的加载。
在 CMD
中,模块的加载是通过 require
函数实现的,该函数接收一个模块标识符和一个回调函数作为参数。当模块的依赖项都加载完成后,回调函数会被执行。例如:
//module1.js 无依赖模块
define(function(require, exports, module) {
const name = "Jack"
module.exports = {
name
}
});
//module2.js 依赖module1.js
define(function(require, exports, module) {
const m1 = require('./module1')
function fullName() {
return m1.name + " Ma"
}
module.exports = {
fullName
}
});
//main.js 引入模块
define(function(require, exports, module){
const m1 = require('./module1')
const m2 = require('./module2')
console.log("module1 --- ", m1, " module2 --- ", m2.fullName());
})
<!-- index.html 引入seajs库 -->
<script src="./lib/sea.js"></script>
<script>
seajs.use("./main")
</script>
2.4 ES6 Module
ES6 Module
是 JavaScript
中官方支持的模块化方案,它采用 import
和 export
关键字导入和导出模块。ES6
模块化支持静态分析,在编译时就能够确定模块的依赖关系,因此可以进行更加高效的打包和压缩。例如:
//module.js
// 导出模块
const a = 1;
const b = 2;
export {
a, b };
// 导入模块
import {
a, b } from './module.js';
export const c = a + b;
需要注意的是,在浏览器中使用 ES6 模块化时,需要在 script 标签上添加 type="module" 属性。例如:
<!-- index.html type设置为module -->
<script type="module" src="./main.js"></script>
ES6 Module
在浏览器端和 Node.js
环境中都可以使用,但需要注意的是,浏览器端对于不同的文件类型有不同的加载方式,需要使用特殊的工具进行编译和打包,常用的工具包括 webpack、Rollup、Parcel
等。