当前位置:首页 > 日记 > 正文

详谈commonjs模块与es6模块的区别

详谈commonjs模块与es6模块的区别

到目前为止,已经实习了3个月的时间了。最近在面试,在面试题里面有题目涉及到模块循环加载的知识。趁着这个机会,将commonjs模块与es6模块之间一些重要的的区别做个总结。语法上有什么区别就不具体说了,主要谈谈引用的区别。

commonjs

对于基本数据类型,属于复制。即会被模块缓存。同时,在另一个模块可以对该模块输出的变量重新赋值。

对于复杂数据类型,属于浅拷贝。由于两个模块引用的对象指向同一个内存空间,因此对该模块的值做修改时会影响另一个模块。

当使用require命令加载某个模块时,就会运行整个模块的代码。

当使用require命令加载同一个模块时,不会再执行该模块,而是取到缓存之中的值。也就是说,commonjs模块无论加载多少次,都只会在第一次加载时运行一次,以后再加载,就返回第一次运行的结果,除非手动清除系统缓存。

循环加载时,属于加载时执行。即脚本代码在require的时候,就会全部执行。一旦出现某个模块被"循环加载",就只输出已经执行的部分,还未执行的部分不会输出。

ES6模块

es6模块中的值属于【动态只读引用】。

对于只读来说,即不允许修改引入变量的值,import的变量是只读的,不论是基本数据类型还是复杂数据类型。当模块遇到import命令时,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。

对于动态来说,原始值发生变化,import加载的值也会发生变化。不论是基本数据类型还是复杂数据类型。

循环加载时,

上面说了一些重要区别。现在举一些例子来说明每一点吧

commonjs

对于基本数据类型,属于复制。即会被模块缓存。同时,在另一个模块可以对该模块输出的变量重新赋值。

// b.jslet count = 1let plusCount = () => { count++}setTimeout(() => { console.log('b.js-1', count)}, 1000)module.exports = { count, plusCount}// a.jslet 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.jsa.js-1 1a.js-2 1b.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.jsa.js-1 1a.js-2 1b.js-1 2 // 1秒后a.js-3 2 // 2秒后, 由于没有定义setter,因此无法对值进行设置。所以还是返回2

对于复杂数据类型,属于浅拷贝。由于两个模块引用的对象指向同一个内存空间,因此对该模块的值做修改时会影响另一个模块。

// b.jslet 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.jsvar 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.jsa.js-1 1a.js-2 2b.js-1 2a.js-3 3b.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.jsexports.done = falselet a = require('./a.js')console.log('b.js-1', a.done)exports.done = trueconsole.log('b.js-2', '执行完毕')// a.jsexports.done = falselet b = require('./b.js')console.log('a.js-1', b.done)exports.done = trueconsole.log('a.js-2', '执行完毕')// c.jslet a = require('./a.js')let b = require('./b.js')console.log('c.js-1', '执行完毕', a.done, b.done)node c.jsb.js-1 falseb.js-2 执行完毕a.js-1 truea.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.jsexport let counter = { count: 1}setTimeout(() => { console.log('b.js-1', counter.count)}, 1000)// a.jsimport { counter } from './b.js'counter = {}console.log('a.js-1', counter)// Syntax Error: "counter" is read-only

虽然不能将counter重新赋值一个新的对象,但是可以给对象添加属性和方法。此时不会报错。这种行为类型与关键字const的用法。

// a.jsimport { counter } from './b.js'counter.count++console.log(counter)// 2

循环加载时,ES6模块是动态引用。只要两个模块之间存在某个引用,代码就能够执行。

// b.jsimport {foo} from './a.js';export function bar() { console.log('bar'); if (Math.random() > 0.5) { foo(); }}// a.jsimport {bar} from './b.js';export function foo() { console.log('foo'); bar(); console.log('执行完毕');}foo();node a.jsfoobar执行完毕// 执行结果也有可能是foobarfoobar执行完毕执行完毕

由于在两个模块之间都存在引用。因此能够正常执行。

以上这篇详谈commonjs模块与es6模块的区别就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。

相关文章

PS合成从水池中钻出的大鲨鱼

PS合成从水池中钻出的大鲨鱼

水池,钻出,大鲨鱼,电脑软件,PS,作者想象力非常丰富,把一些生活中比较常见的物体用一种超自然的方式展示出来,并且画面感、色彩、光影等都非常到位。最终效果制作过程: 12 3 4 阅读全文 1 23 4 阅读全文 1 2 34 阅读全文 最终效果: 1 2 3 4…

js如何编写简单的ajax方法库

js如何编写简单的ajax方法库

方法库,简单,电脑软件,js,ajax,本文实例为大家分享了js编写ajax方法库的具体代码,供大家参考,具体内容如下具体代码~function(){ //ajax:实现ajax请求的公共方法;当一个方法传递的参数过多,而且还不固定,我们使用对象统一传值法(把需要传递的参…

CDR怎么调节色差问题? cdr颜色偏差

CDR怎么调节色差问题? cdr颜色偏差

调节,偏差,解决办法,颜色,电脑软件,cdr文件截图发给客户的时候,发现图片颜色有了变化,与原文件有色差,该怎么调节色差的问题呢?请看下文详细介绍。软件名称:CorelDRAW X8 64位 简体中文安装免费版(附序列号)软件大小:547.9MB更新时间:2016-11-231…

ps怎么给网站添加一个大小合适的LO

ps怎么给网站添加一个大小合适的LO

网站,合适,大小,电脑软件,ps,有很多人在做好一个网站后,却不知道如何给网站做一个好看的LO,这里我给大家分享一下我的经验,希望对大家有所帮助。软件名称:Adobe Photoshop 8.0 中文完整绿色破解版软件大小:150.1MB更新时间:2015-11-041、首先我们…

PS中怎么使用矩形选框工具设计边框

PS中怎么使用矩形选框工具设计边框

边框,工具,矩形,电脑软件,PS,利用PS给图片加相框这样的到时把照片洗出来就特别的有立感了。软件名称:Adobe Photoshop 8.0 中文完整绿色破解版软件大小:150.1MB更新时间:2015-11-041、利用PS打开一张图片并复制这个图层,如图2、选择矩形工具将…

如何添加PPT2010背景音乐与生成视

如何添加PPT2010背景音乐与生成视

背景音乐,视频,电脑软件,  添加PPT2010背景音乐与生成视频成为很多企业在职人员的盲区,也是相对比较复杂的操作过程。将复杂的PPT背景音乐及生成视频简单化、图片化。以下是小编为您带来的关于添加PPT2010背景音乐与生成视频,希望对您有所…

INdesign CS6怎么做渐变羽化效果?

INdesign CS6怎么做渐变羽化效果?

渐变,怎么做,效果,电脑软件,INdesign,INdesign CS6 中插入的图片想要添加渐变羽化效果,该怎么制作呢?下面我们就来看看详细的教程。软件名称:Adobe InDesign CS6 中文免费版软件大小:878.42MB更新时间:2014-05-261、打开一个带有图片的ID文档2、…

ppt2010怎么设置透明色

ppt2010怎么设置透明色

透明,设置,电脑软件,  我们在使用ppt插入图片的时候,有时候需要让图片和背景色融为一体,就需要设置其中的透明色,那么具体要怎么做呢?下面小编来告诉你吧。ppt2010设置透明色的步骤:  插入一张图片到PPT,在图片上“插入”—&…

JavaScript数组_动力节点Java学院

JavaScript数组_动力节点Java学院

数组,学院,节点,动力,电脑软件,JavaScript的Array可以包含任意数据类型,并通过索引来访问每个元素。要取得Array的长度,直接访问length属性:var arr = [1, 2, 3.14, 'Hello', null, true];arr.length; // 6请注意,直接给Array的length赋一个…

QQ空间等级升级快的方法怎么提升QQ

QQ空间等级升级快的方法怎么提升QQ

空间,等级,方法,提升,升级快,  QQ空间等级太低了,而且升级很慢,怎么让它升级快呢?有哪些方法可以提升QQ空间等级?小编为大家整理了提升QQ空间等级的方法,欢迎大家阅读!让QQ空间等级升级快的方法首先我们打开QQ空间,找到应用。让QQ空间等级升级快…

Angular2生命周期钩子函数的详细介

Angular2生命周期钩子函数的详细介

生命周期,钩子函数,详细介绍,电脑软件,Angular每个组件都存在一个生命周期,从创建,变更到销毁。Angular提供组件生命周期钩子,把这些关键时刻暴露出来,赋予在这些关键结点和组件进行交互的能力,掌握生命周期,可以让我们更好的开发Angular应用概述…

Easyui在treegrid添加控件的实现方

Easyui在treegrid添加控件的实现方

方法,控件,电脑软件,Easyui,treegrid, easyui 树加控件最近看了一个easy感觉里面的树搞得还不错,虽然觉得让人有点不灵活的感觉,我们来说说怎么在树种添加控件效果在书中添加需要用到formatter这个属性,可以在加载的时候显示function formatPr…