import与require行为差异原因:为何变量更新结果不一致?
ES模块与CommonJS模块的行为差异原因解析
ES模块测试代码
test.js
// test.js file; let k = 0; let set = () => { k = 1; }; export { k, set };
test1.js
// test1.js import { k, set } from './test.js'; set(); console.log(k); // --> k = 1;
CommonJS模块测试代码
test.js
// test.js let k = 0; let set = () => { k = 1; }; module.exports = { k, set };
test1.js
// test1.js let { k, set } = require('./test.js'); set(); console.log(k); // --> k = 0;
差异原因解析
两种模块规范的核心区别在于导出值的引用逻辑:
ES模块:采用实时绑定机制,
import导入的变量不是值的拷贝,而是直接指向模块内部的原始变量。调用set()修改模块内的k后,导入的k会同步更新,所以最终打印结果为1。CommonJS模块:
module.exports导出的是一个对象,对象里的k是模块内部变量k的值拷贝。当你用解构赋值let { k, set } = require('./test.js')时,当前模块的k已经是独立的副本,后续set()修改的是模块内部的原始k,不会影响这个副本,所以打印结果还是0。
如果想在CommonJS里实现和ES模块一致的效果,有两种方式:
- 给导出对象添加getter,实时返回内部变量值:
// 修改CommonJS的test.js let k = 0; let set = () => { k = 1; }; module.exports = { get k() { return k; }, set };
- 不使用解构,直接保留模块引用:
// 修改CommonJS的test1.js const mod = require('./test.js'); mod.set(); console.log(mod.k); // --> k = 1;
内容的提问来源于stack exchange,提问作者Haydar C.
相关产品推荐
相关产品推荐

