ES Module 和 CommonJS 有什么区别

先理解原理和示例,再练习完整口述与追问。

从语法、加载与执行、依赖分析、导出绑定和运行环境回答。不要简单背“一个同步、一个异步”;浏览器、Node 和打包产物的行为需要分别看。

**追加检查:**let / const / var、暂时性死区、类型判断、引用相等、Map / Set、可选链、空值合并、浮点精度。

CommonJS 使用 require 与 module.exports,通常在执行到 require 时同步加载并执行模块,结果按解析到的文件身份缓存。导出对象是引用,解构取出的某个属性值却不会自动跟随后续重新赋值。ESM 使用静态 import/export 建立模块关系,导入是只读的活绑定;具体加载、链接和异步求值行为由宿主与模块内容决定。

CommonJS 中 const mod = require('./counter') 后,mod.count 能看到同一导出对象属性后续的修改;const {count} = require(...) 只取得当时属性值。若模块后续将 module.exports 换成另一个对象,之前拿到的引用也不会自动切换。ESM 的 export let count 被更新时,合法导入绑定能够反映新值,但导入方不能直接赋值修改该绑定。

“CJS 永远值拷贝,ESM 永远编译时执行”都不准确。Node 的 package type、扩展名、exports 和互操作规则要结合版本说明,不能拿打包器补全的路径规则当原生 Node 规则。

ES Module 使用 import/export,静态导入便于构建器分析依赖,导入绑定具有实时关联语义;CommonJS 通过 require 和 module.exports 运行时加载模块,require 通常拿到导出值或对象引用,并按模块缓存。不能简单说 CommonJS 导出一定是深拷贝;改导出对象的属性与后续替换 module.exports 的结果也不同。静态 import、动态 import()、Node require 和浏览器模块加载的调度不一样,回答时要先限定环境。