模块化(AMD、ES6、CommonJS)
约 1605 字大约 5 分钟
2025-03-12
总结
ES6 模块化 是各大主流框架、打包工具的 首选,模块化开发具有以下优点:
- 提高开发效率:通过将系统划分为独立的模块,开发人员可以并行开发,同时处理不同的模块,加快开发速度。
- 降低维护成本:模块化使得每个模块的功能和职责更加明确,便于发现和修复问题,减少了系统的维护成本。
- 提高代码可读性和可维护性:模块化使得代码更加模块化,易于阅读和理解。同时,由于每个模块的功能相对较小,更容易进行单元测试和集成测试。
- 重用代码:通过将通用功能封装在独立的模块中,可以在不同的项目中进行重用,减少了重复开发的工作量。
- 更好的团队协作:模块化开发鼓励分工合作,不同的团队成员可以负责不同的模块,便于协作开发。
一、什么是模块化
模块化编程是一种编程范式,它将复杂的应用程序划分为更小的、独立的、可重复使用的代码块,这些代码块被称为模块。 每个模块都拥有其自身的功能和数据,它们通过定义清晰的接口与其他模块进行交互。
这种方法有助于代码的组织,提高了代码的复用性和可维护性,同时使得团队协作开发时可以更加清晰地分配任务。
在 JavaScript 中,有几种常见的方式可以实现模块化开发:
二、命名空间模式(namespace)
通过创建一个某个值域下的 对象 或 函数(闭包) 作为命名空间,将相关的变量和函数放置在该对象下。这种方式可以有效避免命名冲突,但需要手动管理命名空间,容易造成代码的冗余和不易维护。
三、AMD(Asynchronous Module Definition) 异步加载
是一种异步模块定义的规范,主要用于在浏览器中异步加载模块。使用 AMD
规范的库和工具有 RequireJS
。它允许定义模块,并通过异步加载依赖模块,以实现模块化的开发和加载。
缺点是代码嵌套层级加深、繁琐不好维护,不如 CommonJS 和 ES6 好用
// define.js
define(["dependency1", "dependency2"], function (dep1, dep2) {
// 模块逻辑,可以使用dep1和dep2
return {
doSomething: function () {
// 使用依赖项进行操作
},
};
});
// main.js
require(["define"], function (definedModule) {
// 使用define模块
definedModule.doSomething();
});
四、CommonJS 单例模式 缓存机制 同步加载
CommonJS 是一种同步的模块加载规范,主要用于 Node.js 环境。使用 CommonJS 的模块可以直接导入和导出模块,以供其他模块使用。使用 module.exports 和 exports 导出,使用 require()导入。
通常依赖 node.js 环境,browserify
插件主要用来将 Common.js 转化为浏览器可以识别的语法
注意
文件一般就默认是一个模块,一个模块里只能有一个 module.exports,但是 exports 可以有多个
语法 1 :module.exports = 变量名
【只适用于导出一个变量】
语法 2 :module.exports = {key:value,key:value,xxx}
【通用】
语法 2 可以简写成 module.exports = {value,value,xxx}
【直接把变量放进来】
1、导出 module.exports 和 exports
// 声明一个变量
let abc = 100;
// 声明一个方法
const sayHello = () => {
console.log("hello world 你好哈哈哈");
};
// 只能暴露一个,如果写多次,就会被覆盖 : 下面的两行只能留一行
module.exports = abc;
module.exports = sayHello;
// 通过对象的方式导出变量和方法,起别名
module.exports = {
abc1: abc,
sayHello1: sayHello,
};
// 通过对象的方式导出变量和方法
module.exports = {
abc,
sayHello,
};
exports.abc;
exports.sayHello;
2、导入 require
// counter.js
let count = 0;
exports.increment = function () {
count++;
return count;
};
js;
// app.js
const counter1 = require("./counter");
const counter2 = require("./counter");
// 虽然使用require引入了两次,但是使用的是同一份实例,使用了闭包引用全局变量
console.log(counter1.increment()); // 输出 1
console.log(counter2.increment()); // 输出 2
五、ES6 模块化 同步加载 异步加载
在 ECMAScript 6 中,引入了原生的模块化支持。可以使用 import 关键字导入模块,使用 export 关键字导出模块。ES6 模块化有静态分析的优势,可以在编译时确定模块的依赖关系,提供更好的性能和开发体验。
ES6 模块化主要由 export和 import 两个命令构成:
1、导出 export
用于导出,即哪些变量、函数或类可以被外部访问。有多种形式:
注意
默认导出的时候,如果有对象或函数未被添加到导出清单里,需要使用 * as xx_name
语法引入该部分。再用 xx_name.unExportModule
去使用
1.1、命名导出
export { m1, m2, …, mN };
1.2、默认导出(每个模块只能有一个默认导出)。
export default expression;
export default { m1, m2, …, mN };
1.3、导出一个外部文件,相当于把一个文件引入后,再导出其内容
export * from "xxx.js";
export { m1, m2 } from "xxx.js";
2、导入 import
2.1、同步导入
同步导入支持解构,支持按需导入、整体导入。
import { m1, m2, m3 } from "xxx.js"; // 按需导入
import module from "xxx.js"; // 整体导入
import * as module1 from "xxx.js"; // 整体导入并命名
2.3、异步导入
异步导入时,返回的对象为 Promise。
if (condition) {
import("./moduleA").then((module) => {
// 使用 module do some thing
});
}
选择适合的模块化方式主要取决于项目的需求和环境。在现代的 JavaScript 开发中,使用 ES6 模块化 是各大主流框架 最推荐 的方式,但也可以根据具体情况选择其他方式。
六、ES6 模块化和 CommonJS 的区别
对比项 | CommonJS | ES6 模块 |
---|---|---|
语法 | 导出模块module.exports 或 exports ,引入模块: require | 导出模块export ,引入模块import |
运行环境 | 依赖 Node.js 环境 或者支持 CommonJS 的运行环境 | 可以直接运行在浏览器环境中,可以通过 Babel 等工具转化为浏览器可以执行的 |
功能特性 | 同步加载,动态导入不方便,可以引入第三方库去实现 | 支持同步、异步加载,静态分析,支持运行时动态导入 |
更新日志
e7112
-1于