当前位置:   article > 正文

CommonJs 和 ESModule 的 区别整理_exports.foo = foo

exports.foo = foo

1. exports 和 module.exports 的区别

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

引用:

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

2. commonJs 和 esModule 的区别

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

commonJs 输出值拷贝

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

esModule 输出值引用

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

commonJs 输出的浅拷贝验证

  1. /*************** a.js**********************/
  2. const foo = {
  3. count: 0
  4. }
  5. //module.exports的foo属性为 foo 对象的浅拷贝,指向同一个内存中
  6. exports.foo=foo;
  7. window.setTimeout(()=>{
  8. foo.count += 1
  9. console.log('changed foo')
  10. },1000)
  11. /*************** b.js**********************/
  12. const { foo } = require('./a.js')
  13. console.log('foo', foo);//'foo',{count: 0}
  14. window.setTimeout(()=>{
  15. console.log('after 2s foo', foo);//'after 2s foo ',{count: 1}
  16. }, 2000)
  17. 复制代码

commonJs 输出时的危险操作

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

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

  1. /*************** a.js**********************/
  2. const foo = {
  3. count: 0
  4. }
  5. exports.foo=foo; //此时foo指向 {count: 0}的内存地址
  6. window.setTimeout(()=>{
  7. //改变 foo 的内存指向
  8. exports.foo='haha';
  9. },1000)
  10. /*************** b.js**********************/
  11. const { foo } = require('./a.js'); //拷贝了 foo属性指向 {count: 0} 内存地址的引用
  12. console.log('foo', foo);//'foo',{count: 0}
  13. window.setTimeout(()=>{
  14. //看!并没有改变!
  15. console.log('after 2s foo', foo);//'after 2s foo ',{count: 0}
  16. }, 2000)
  17. 复制代码

改进:

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

进阶:

  1. /*************** child.js**********************/
  2. let foo = 1
  3. setTimeout(()=>{
  4. foo=2;
  5. exports.foo= foo
  6. },1000)
  7. exports.foo=foo
  8. /*******************index.js***************************/
  9. var test =require('./child');
  10. console.log(test.foo);// 1
  11. setTimeout(()=>{
  12. console.log(test.foo) // 2
  13. },2000)
  14. 复制代码

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

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

3. ES6 模块加载 CommonJS 模块

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

4. CommonJS 模块加载 ES6 模块

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

  1. // es.mjs
  2. let foo = { bar: 'my-default' };
  3. export default foo;
  4. // cjs.js
  5. const es_namespace = await import('./es.mjs');
  6. // es_namespace = {
  7. // get default() {
  8. // ...
  9. // }
  10. // }
  11. console.log(es_namespace.default);
  12. // { bar:'my-default' }
  13. 复制代码

参考链接:


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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/140302?site
推荐阅读
相关标签
  

闽ICP备14008679号