对CommonJS和ES6 模块异同的思考(含循环加载)
前言
最近在学习的过程中了解到了一些CommonJS的模块机制,借机总结一下其与ES6模块的异同,本文参考了博客园博主凯斯keith 的文章,也参考了博客园博主forcheng>的文章,详情点击如上链接。
CommonJS和ES6 模块异同
不同
CommonJS:
- 使用
require
引入模块,一个文件就是一个模块 - 对于模块中简单类型的变量:属于对原变量的复制;在导入该模块的文件里对该变量的修改不会同步到原模块,在原模块里对变量进行修改也不会影响导入该模块的文件。
//a.js文件 let count = 0; let plusCount = () => { count++ }; setTimeout(() => { console.log('a.js', count) }, 1000) plusCount();//调用函数 module.exports = {//导出模块 count, plusCount } //b.js文件 let mod = require('./1.a_commonJS')//导入a模块 console.log('b.js-1', mod.count)//输出b.js-1 0 mod.plusCount()// 调用之后,b模块的count不受影响,a的count发生改变 console.log('b.js-2', mod.count)//输出b.js-2 0 mod.count = 4// 手动对count进行赋值 console.log('b.js-3', mod.count)//输出 b.js-3 4 // 最后还会输出:a.js 1 //在b.js里面调用plusCount函数,前后输出count发现count没有改变,但a里面的count发生了改变 //这就说明了:对于简单数据类型,CommonJS模块传递的是值的复制,对一个值的修改不会影响另外一个值。
- 对于复杂类型的变量:属于对原变量的浅拷贝,指向同一个地址空间,对变量的修改会相互影响
- CommonJS是加载时执行:遇到
require
的时候,就会全部执行,生成一个对象存在内存里,然后从这个对象的属性上取需要的值 - 如果
require
多次导入同一个模块,则只执行一次(执行时缓存)
ES6
- 导入的值只是原模块的
动态只读引用
- 对于只读:不允许修改引入的模块的值
- 对于动态:原始模块发生变化,import加载的值也会变化
- ES6模块是编译时输出接口:遇到
import
时,输出一个动态只读引用,等到真的要用这个值的时候(运行时),再通过这个引用到模块中取值。
相同
- CommonJS和ES6 Module都可以对引⼊的对象进⾏赋值,即对对象内部属性的值进行改变。
- 遇到多次导入,只执行一次(CommonJS会缓存,ES6不会)
说一说两者循环加载的处理机制
CommonJS循环加载
遇到循环加载时,输出已经执行的部分,没有执行的部分不予输出
//a.js console.log('a starting'); exports.done = false; const b = require('./b.js'); console.log('in a, b.done = %j', b.done); exports.done = true; console.log('a done'); // b.js console.log('b starting'); exports.done = false; const a = require('./a.js'); console.log('in b, a.done = %j', a.done); exports.done = true; console.log('b done'); //// main.js console.log('main starting'); const a = require('./a.js'); const b = require('./b.js'); console.log('in main, a.done = %j, b.done = %j', a.done, b.done);
输出为:
次数采用注释的方式说明了执行顺序,需要耐心一点看
main starting #加载main.js a.starting #在main.js中开始加载a模块 b.starting #在a.js中开始加载b模块 # 加载b时遇到再次对a的加载,发现循环加载 输出已经执行的部分 #此时还处在b模块中 in b,a.done=false #这是因为上一个代码块的第二行 b done #返回到a模块接着第四行执行 in a,b.done=true #这是因为上一个代码块的第14行 a done #返回到main #遇到对b模块的加载,不再执行(CommonJS机制) in main,a.done=true,b.done=true#这是因为6和14行
ES6循环加载
ES6处理"循环加载"与CommonJS有本质的不同。ES6根本不会关心是否发生了"循环加载",只是生成一个指向被加载模块的引用,需要开发者自己保证,真正取值的时候能够取到值。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!