到目前为止,已经实习了3个月的时间了。最近在面试,在面试题里面有题目涉及到模块循环加载的知识。趁着这个机会,将commonjs模块与es6模块之间一些重要的的区别做个总结。语法上有什么区别就不具体说了,主要谈谈引用的区别。
commonjs
对于基本数据类型,属于复制。即会被模块缓存。同时,在另一个模块可以对该模块输出的变量重新赋值。
对于复杂数据类型,属于浅拷贝。由于两个模块引用的对象指向同一个内存空间,因此对该模块的值做修改时会影响另一个模块。
当使用require命令加载某个模块时,就会运行整个模块的代码。
当使用require命令加载同一个模块时,不会再执行该模块,而是取到缓存之中的值。也就是说,commonjs模块无论加载多少次,都只会在第一次加载时运行一次,以后再加载,就返回第一次运行的结果,除非手动清除系统缓存。
循环加载时,属于加载时执行。即脚本代码在require的时候,就会全部执行。一旦出现某个模块被"循环加载",就只输出已经执行的部分,还未执行的部分不会输出。
ES6模块
es6模块中的值属于【动态只读引用】。
对于只读来说,即不允许修改引入变量的值,import的变量是只读的,不论是基本数据类型还是复杂数据类型。当模块遇到import命令时,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。
对于动态来说,原始值发生变化,import加载的值也会发生变化。不论是基本数据类型还是复杂数据类型。
循环加载时,
上面说了一些重要区别。现在举一些例子来说明每一点吧
commonjs
对于基本数据类型,属于复制。即会被模块缓存。同时,在另一个模块可以对该模块输出的变量重新赋值。
// b.js let count = 1 let plusCount = () => { count++ } setTimeout(() => { console.log('b.js-1', count) }, 1000) module.exports = { count, plusCount } // a.js let mod = require('./b.js') console.log('a.js-1', mod.count) mod.plusCount() console.log('a.js-2', mod.count) setTimeout(() => { mod.count = 3 console.log('a.js-3', mod.count) }, 2000) node a.js a.js-1 1 a.js-2 1 b.js-1 2 // 1秒后 a.js-3 3 // 2秒后
以上代码可以看出,b模块export的count变量,是一个复制行为。在plusCount方法调用之后,a模块中的count不受影响。同时,可以在b模块中更改a模块中的值。如果希望能够同步代码,可以export出去一个getter。
// 其他代码相同 module.exports = { get count () { return count }, plusCount } node a.js a.js-1 1 a.js-2 1 b.js-1 2 // 1秒后 a.js-3 2 // 2秒后, 由于没有定义setter,因此无法对值进行设置。所以还是返回2
对于复杂数据类型,属于浅拷贝。由于两个模块引用的对象指向同一个内存空间,因此对该模块的值做修改时会影响另一个模块。
// b.js let obj = { count: 1 } let plusCount = () => { obj.count++ } setTimeout(() => { console.log('b.js-1', obj.count) }, 1000) setTimeout(() => { console.log('b.js-2', obj.count) }, 3000) module.exports = { obj, plusCount } // a.js var mod = require('./b.js') console.log('a.js-1', mod.obj.count) mod.plusCount() console.log('a.js-2', mod.obj.count) setTimeout(() => { mod.obj.count = 3 console.log('a.js-3', mod.obj.count) }, 2000) node a.js a.js-1 1 a.js-2 2 b.js-1 2 a.js-3 3 b.js-2 3
以上代码可以看出,对于对象来说属于浅拷贝。当执行a模块时,首先打印obj.count的值为1,然后通过plusCount方法,再次打印时为2。接着在a模块修改count的值为3,此时在b模块的值也为3。
3.当使用require命令加载某个模块时,就会运行整个模块的代码。
4.当使用require命令加载同一个模块时,不会再执行该模块,而是取到缓存之中的值。也就是说,commonjs模块无论加载多少次,都只会在第一次加载时运行一次,以后再加载,就返回第一次运行的结果,除非手动清除系统缓存。
5.循环加载时,属于加载时执行。即脚本代码在require的时候,就会全部执行。一旦出现某个模块被"循环加载",就只输出已经执行的部分,还未执行的部分不会输出。
3, 4, 5可以使用同一个例子说明 // b.js exports.done = false let a = require('./a.js') console.log('b.js-1', a.done) exports.done = true console.log('b.js-2', '执行完毕') // a.js exports.done = false let b = require('./b.js') console.log('a.js-1', b.done) exports.done = true console.log('a.js-2', '执行完毕') // c.js let a = require('./a.js') let b = require('./b.js') console.log('c.js-1', '执行完毕', a.done, b.done) node c.js b.js-1 false b.js-2 执行完毕 a.js-1 true a.js-2 执行完毕 c.js-1 执行完毕 true true
仔细说明一下整个过程。
在Node.js中执行c模块。此时遇到require关键字,执行a.js中所有代码。
在a模块中exports之后,通过require引入了b模块,执行b模块的代码。
在b模块中exports之后,又require引入了a模块,此时执行a模块的代码。
a模块只执行exports.done = false这条语句。
回到b模块,打印b.js-1, exports, b.js-2。b模块执行完毕。
回到a模块,接着打印a.js-1, exports, b.js-2。a模块执行完毕
回到c模块,接着执行require,需要引入b模块。由于在a模块中已经引入过了,所以直接就可以输出值了。
结束。
从以上结果和分析过程可以看出,当遇到require命令时,会执行对应的模块代码。当循环引用时,有可能只输出某模块代码的一部分。当引用同一个模块时,不会再次加载,而是获取缓存。
ES6模块
es6模块中的值属于【动态只读引用】。只说明一下复杂数据类型。
对于只读来说,即不允许修改引入变量的值,import的变量是只读的,不论是基本数据类型还是复杂数据类型。当模块遇到import命令时,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。
对于动态来说,原始值发生变化,import加载的值也会发生变化。不论是基本数据类型还是复杂数据类型。
// b.js export let counter = { count: 1 } setTimeout(() => { console.log('b.js-1', counter.count) }, 1000) // a.js import { counter } from './b.js' counter = {} console.log('a.js-1', counter) // Syntax Error: "counter" is read-only
虽然不能将counter重新赋值一个新的对象,但是可以给对象添加属性和方法。此时不会报错。这种行为类型与关键字const的用法。
// a.js import { counter } from './b.js' counter.count++ console.log(counter) // 2
循环加载时,ES6模块是动态引用。只要两个模块之间存在某个引用,代码就能够执行。
// b.js import {foo} from './a.js'; export function bar() { console.log('bar'); if (Math.random() > 0.5) { foo(); } } // a.js import {bar} from './b.js'; export function foo() { console.log('foo'); bar(); console.log('执行完毕'); } foo(); node a.js foo bar 执行完毕 // 执行结果也有可能是 foo bar foo bar 执行完毕 执行完毕
由于在两个模块之间都存在引用。因此能够正常执行。
以上这篇详谈commonjs模块与es6模块的区别就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。
更新日志
- 中国武警男声合唱团《辉煌之声1天路》[DTS-WAV分轨]
- 紫薇《旧曲新韵》[320K/MP3][175.29MB]
- 紫薇《旧曲新韵》[FLAC/分轨][550.18MB]
- 周深《反深代词》[先听版][320K/MP3][72.71MB]
- 李佳薇.2024-会发光的【黑籁音乐】【FLAC分轨】
- 后弦.2012-很有爱【天浩盛世】【WAV+CUE】
- 林俊吉.2012-将你惜命命【美华】【WAV+CUE】
- 晓雅《分享》DTS-WAV
- 黑鸭子2008-飞歌[首版][WAV+CUE]
- 黄乙玲1989-水泼落地难收回[日本天龙版][WAV+CUE]
- 周深《反深代词》[先听版][FLAC/分轨][310.97MB]
- 姜育恒1984《什么时候·串起又散落》台湾复刻版[WAV+CUE][1G]
- 那英《如今》引进版[WAV+CUE][1G]
- 蔡幸娟.1991-真的让我爱你吗【飞碟】【WAV+CUE】
- 群星.2024-好团圆电视剧原声带【TME】【FLAC分轨】