§ CJS 和 ESM的区别
CJS ==> 全称CommonJS
ESM ==> 全称ECMAScript Modules
1.语法:
CJS: 使用 require()
来导入模块,使用 module.exports
或 exports
来导出
ESM: 使用 import
和 export
关键字
2.运行时与编译时:
CJS: 在运行时解析依赖
ESM: 在编译时解析依赖
3.异步与同步:
CJS: 同步加载模块
ESM: 支持异步加载
4.作用域:
CJS: 每个模块都有自己的作用域
ESM: import 和 export 必须位于模块作用域
5.互操作性:
CJS: 在Nodejs中广泛使用,但原生浏览器不支持
ESM: 既可以在浏览器中使用,也可以在nodejs中使用
§ CJS 和 ESM 分别是怎么解决循环依赖的
循环依赖(或称为循环引用) 是一个在模块系统中常见的问题,不同的模块系统有不同的方式来处理这个问题
CJS:
在 CommonJS 中,当发生循环依赖时,模块系统会返回到目前为止已经解析(并执行)的部分。这意味着,在循环依赖的情况下,你可能得到一个不完全初始化的模块
假设有两个模块 A 和 B,它们相互依赖:
// A.js
const B = require('./B');
exports.name = 'Module A';
// B.js
const A = require('./A');
exports.name = 'Module B';
在这种情况下,当你尝试 require('./A') 或 require('./B'),模块系统会尝试解析两者,但由于循环依赖,它会返回一个不完全初始化的模块
ESM:
ESM 采用了一种不同的方法来处理循环依赖。由于 ESM 在编译时解析依赖,它能更好地处理这种情况。在 ESM 中,导入的值是只读引用,而不是值的拷贝。这意味着,即使存在循环依赖,你也会得到预期的结果
// A.js
import { name as BName } from './B.js';
export const name = 'Module A';
// B.js
import { name as AName } from './A.js';
export const name = 'Module B';
在这个例子中,由于 ESM 的静态解析特性,循环依赖会被正确地解析,而不会导致不完全初始化的模块
总结:
CJS: 在运行时解析模块,可能导致不完全初始化的模块。
ESM: 在编译时解析模块,能更好地处理循环依赖。