1. exports 和 module.exports 的区别

  • module.exports 默认值为{}
  • exports 是 module.exports 的引用
  • exports 默认指向 module.exports 的内存空间
  • require() 返回的是 module.exports 而不是 exports
  • 若对 exports 重新赋值,则断开了 exports 对 module.exports 的指向

引用:

  • require 和 import 都可引用
//foo.js
exports.foo="foo"
//等同于
module.exports.foo="foo"//bar.js
const { foo } = require('./foo.js')
console.log(foo);//'foo'复制代码
//foo.js
exports={foo: 'foo'
}//bar.js
const { foo } = require('./foo.js')
//reuqire 返回的是 module.exports 对象, 默认为 {}
console.log(foo);//undefined复制代码

2. commonJs 和 esModule 的区别

  • commonJs是被加载的时候运行,esModule是编译的时候运行
  • commonJs输出的是值的浅拷贝,esModule输出值的引用
  • commentJs具有缓存。在第一次被加载时,会完整运行整个文件并输出一个对象,拷贝(浅拷贝)在内存中。下次加载文件时,直接从内存中取值

commonJs 输出值拷贝

/*************** a.js**********************/
let count = 0
exports.count = count; // 输出值的拷贝
exports.add = ()=>{//这里改变count值,并不会将module.exports对象的count属性值改变count++;
}/*************** b.js**********************/
const { count, add } = require('./a.js')
//在支持es6模块的环境下等同于
import { count, add } from './a.js'console.log(count) //0
add();
console.log(count)//0
复制代码

esModule 输出值引用

/*************** a.js**********************/
export let count = 0;//输出的是值的引用,指向同一块内存
export const add = ()=>{count++;//此时引用指向的内存值发生改变
}/*************** b.js**********************/
import { count, add } from './a.js'console.log(count) //0
add();
console.log(count)//1
复制代码

commonJs 输出的浅拷贝验证

/*************** a.js**********************/
const foo = {count: 0
}
//module.exports的foo属性为 foo 对象的浅拷贝,指向同一个内存中
exports.foo=foo;window.setTimeout(()=>{foo.count += 1console.log('changed foo')
},1000)/*************** b.js**********************/
const  { foo }  = require('./a.js')console.log('foo', foo);//'foo',{count: 0}
window.setTimeout(()=>{console.log('after 2s foo', foo);//'after 2s foo ',{count: 1}
}, 2000)
复制代码

commonJs 输出时的危险操作

其实上个栗子中的 const { foo } = require('./a.js') 或者 const foo = require('./a.js').foo 写法是相当危险的。因为commonJs输出的值的拷贝,若后面在a.js中 对foo的内存指向作出改动,则不能及时更新。

我们将上面的栗子做个小改动:

/*************** a.js**********************/
const foo = {count: 0
}
exports.foo=foo; //此时foo指向 {count: 0}的内存地址
window.setTimeout(()=>{//改变 foo 的内存指向exports.foo='haha';
},1000)/*************** b.js**********************/
const  { foo }  = require('./a.js'); //拷贝了 foo属性指向 {count: 0} 内存地址的引用console.log('foo', foo);//'foo',{count: 0}
window.setTimeout(()=>{//看!并没有改变!console.log('after 2s foo', foo);//'after 2s foo ',{count: 0}
}, 2000)
复制代码

改进:

/*************** b.js**********************/
const test = require('./a.js');
//test 拷贝了 整个输出对象{foo:{count: 0} }内存地址的引用
//当内存中的属性值发生变化时,可以拿到最新的值,因为指向的是同一片内存console.log('foo', test.foo);//'foo',{count: 0}
window.setTimeout(()=>{//保证获取到的是最新的console.log('after 2s foo', test.foo);//'after 2s foo ','haha'
}, 2000)复制代码

进阶:

/*************** child.js**********************/
let foo = 1setTimeout(()=>{foo=2;exports.foo= foo
},1000)
exports.foo=foo/*******************index.js***************************/
var test =require('./child');console.log(test.foo);// 1setTimeout(()=>{console.log(test.foo) // 2
},2000)
复制代码

将child.js中的输出方式做一下改动,结果就变了。

/*************** child.js**********************/
let foo = 1setTimeout(()=>{foo=2;module.exports={foo};//注意:指向新内存 {foo:2}
},1000)
module.exports={foo}; //指向内存 {foo:1}/*******************index.js***************************/
var test =require('./child');// 浅拷贝,指向的还是{foo:1}的内存,并缓存在内存中console.log(test.foo);// 1 //从缓存的内存中取值setTimeout(()=>{console.log(test.foo) // 1 //从缓存的内存中取值
},2000)复制代码

3. ES6 模块加载 CommonJS 模块

module.exports 等同于 export default 可以用 import 引入

4. CommonJS 模块加载 ES6 模块

CommonJS 模块加载 ES6 模块,不能使用require命令,而要使用import()函数。

// es.mjs
let foo = { bar: 'my-default' };
export default foo;// cjs.js
const es_namespace = await import('./es.mjs');
// es_namespace = {
//   get default() {
//     ...
//   }
// }
console.log(es_namespace.default);
// { bar:'my-default' }
复制代码

参考链接:

  • 阮大大:es6.ruanyifeng.com/#docs/modul…
  • JS基本数据类型和引用数据类型的区别及深浅拷贝:www.cnblogs.com/c2016c/arti…

作者:一颗白菜
链接:https://juejin.im/post/6844903598480965646
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

CommonJs 和 ESModule 的 区别整理相关推荐

  1. CommonJs和ESModule的区别及优缺点

    说起js,就不得不提及模块化编程,简单来说,模块化就像造汽车一样,有人造轮子,有人早车外壳,最后将各自造好的东西拼到一起组装成汽车,充分体现了分工合作的思想. 模块化的作用 使用模块化是为了将一个很大 ...

  2. JS高级笔记:CommonJs与ESModule的区别

    区别: 两者的模块导入导出语法不同,CommonJs是通过module.exports,exports导出,require导入:ESModule则是export导出,import导入. CommonJ ...

  3. Webpack 打包commonjs 和esmodule 模块的产物对比

    这篇文章不涉及 Webpack 的原理,只是观察下 Webpack 对 commonjs 和 esmodule 模块打包后的产物,读完后会对模块系统有个更深的了解. 环境配置 Webpack 只配置入 ...

  4. Commonjs和Esmodule

    一.写在前面 commonjs和esmodule是目前前端主要的模块化方案,下面将具体总结一下,以及两者之间的不同之处. 二.commonjs 2.1 commonjs也叫cjs,在node中每一个j ...

  5. commonjs 与 esm 的区别

    js 社区存在多种模块化规范,其中最常使用到的是 node 本身实现的 commonjs 和 es6 标准的 esm. commonjs 和 esm 存在多种根本上的区别,详细的比较在阮一峰的< ...

  6. 各种简单滤波的区别整理

    各种简单滤波的区别整理 1. 均值滤波(对高斯噪声具有较好的处理效果) 均值滤波在去噪声的同时会有如下缺点:边界模糊效应明显.细节丢失比较严重:无法去掉噪声,只能微弱的减弱它. 高斯噪声:高斯噪声是指 ...

  7. ios和android交互差异,Android 和 iOS 主要交互区别整理

    我简单整理了一下Android 和 iOS 主要的交互区别,如果有遗漏欢迎批评补充. 我总结有下面五类区别: 一.界面布局形式的差异 1 iOS 的 Tab Bar 在iOS应用内最多用Tab Bar ...

  8. C语言和C++的区别整理详解!

    c和c++主要区别 根据书中的描述,进行了整理 推荐一个我自己的C/C++交流裙815393895 1. 源代码文件的扩展名 摘自1.4.1 C++实现源代码文件的扩展名UNIXC.cc.cxx.cG ...

  9. 面试题:Commonjs 和 Es Module区别

    一 前言 今天我们来深度分析一下 Commonjs 和 Es Module,希望通过本文的学习,能够让大家彻底明白 Commonjs 和 Es Module 原理,能够一次性搞定面试中遇到的大部分有关 ...

最新文章

  1. Android入门教程 (二) 第一个App HelloWorld
  2. 航天智慧物流南北分区赛通知
  3. Eclipse高级使用技巧
  4. MySql某一列累计查询
  5. dev编译按钮是灰色_提升 50% 的编译速度!阿里零售通 App 工程提效实践
  6. linux屏幕分辨率文件,Ubuntu 16.04 LTS设置屏幕分辨率显示Unknown display 解决
  7. 什么样的人不适合互联网创业
  8. 用c语言实现键盘画图,用C实现键盘画图.doc
  9. 关于算法--蛮力法篇--选择排序
  10. java static 执行顺序
  11. autocoder自动代码生成器_Spring Boot 集成MyBatis Plus代码生成器
  12. Vuex 实战:如何在大规模 Vue 应用中组织 Vuex 代码 | 掘金技术征文
  13. MarkDown学习手册
  14. vue报错elementUI使用datepicker报错Avoid mutating a prop directly since the value will be overwritten whene
  15. web3py earliest、latest、pending
  16. 有限域(2)——理想和商环
  17. 软考-高项-论文-信息系统项目的质量管理
  18. MAX7456 OSD
  19. FPGA芯片的GTX/GTH/GTY/GTP/GTZ/GTM高速信号有什么区别?
  20. [Tableau] 直方图绘制

热门文章

  1. AI教程之:渐变效果
  2. spry提示信息设置html,[原]Spry框架:表单验证构件
  3. 14、Spark_RDD算子——CombineByKey_ReduceByKey转换
  4. 如何修改mtp模式在电脑上显示的存储容量大小?
  5. 最小割与最大流(mincut amp; maxflow)
  6. 【测试工程师】关于软件测试的10条建议
  7. 对于配置JAVA_HOME
  8. 管道、管程、管态的区别
  9. 代码实现对麻将的听牌分析(判断什么牌能胡)
  10. 数据挖掘经典十大算法_条件熵、信息增益介绍