exports和module.exports的区别

CommonJS模块规范中,通过require来引入外部模块,通过exportsmodule.exports来导出模块

  • 使用require引入模块时,会得到模块导出的内容,可以用一个变量接收他

  • 比如有两个文件import.jsexport.js,现在要在import.js中引入export.js

    • export.js

      console.log('我是export.js');
      exports.hello = 'world';
      
      module.exports.year = '2021';
      
      setTimeout(() => {
          console.log(exports);
      },2000);
      
      console.log(exports === module.exports);
      
    • import.js中引入export.js

      console.log('我是import.js');
      //require('./export');
      const lib = require('./export');
      console.log('我是export.js导出的内容:', lib);
      
      // 给lib添加属性
      lib.additional = 'test';
      
    • 在控制台执行node import.js可以得到
      exports和module.exports的区别

  • 在node官方文档中有提到,在执行模块代码之前,Node.js 会用下面的函数包装器对其进行包装

    (function(exports,require,module,__filename,__dirname){
      ...
    })
    
    • 这样有助于将*变量(用var,const或定义let)保持在模块而不是全局对象的范围内。
    • 有助于提供一些实际特定于模块的全局变量,例如:
      • 实现者可以用moduleexports对象实现模块值的导出。
      • 便利变量__filename__dirname,包含模块的绝对文件名和目录路径。
  • 从上面可以看出exportsmodule是一个模块特有的全局变量,并且module也有一个exports属性,使用这个属性可以实现和exports一样的功能

exportsmodule.exports的区别

  • 在执行console.log(exports === module.exports);的时候,得到的结果为true

  • 说明exportsmodule.exports是相同的,指向同一个内存地址

  • 注意,这个时候执行console.log('我是export.js导出的内容:', lib);到的内容还是

    { hello: 'world', year: '2021' }
    
    • 导出的内容包含了exports.hellomodule.exports.year
  • 这时候,改变一下module.exports导出的内容,其他的不变

    module.exports = {
        year: '2021'
    };
    
  • 打印一下得到
    exports和module.exports的区别

    • 这会console.log(exports === module.exports);的结果为falseexportsmodule.exports不相等了
    • 执行console.log('我是export.js导出的内容:', lib);,得到的导出内容也只有module.exports导出的了
    • 定时器里打印的exports也只有exports.hello导出的内容了
  • 当改变module.exports导出的内容为一个对象后,让 module.exports指向了新的内存地址,使得他俩不再相等

  • 执行import.js得到的export.js导出的内容只有year:2021也说明,只有module.exports 的变量被返回了,前面导出的内容还有hello:world是因为之前他们是指向同一个内存地址的

  • module.exports指向了新的内存地址后,在改变一下定时器打印的内容为console.log(module.exports)

  • 执行import.js可以得到
    exports和module.exports的区别

  • 跟上面的打印结果作对比可以发现,在import.js中给lib添加的新属性添加到module.exports身上了

  • 在做一个实验,假设module.exportsexports还是指向同一个内存地址,有如下代码

    console.log('我是export.js');
    exports.hello = 'world';
    
    module.exports.year = '2020';
    exports.year = '2022';
    
    setTimeout(() => {
        console.log(exports);
    },2000);
    
    console.log(exports === module.exports);
    
    • 执行import.js可以得到
      exports和module.exports的区别
    • 会发现module.exports.year的值被exports改变了
结论
  • exports 对象是 module 对象的一个属性,在初始时 module.exportsexports 指向同一块内存区域
  • 模块导出的是 module.exports , exports 只是对它的引用,在不改变exports 内存的情况下,修改exports 的值可以改变 module.exports 的值
  • 导出时尽量使用 module.exports ,以免因为各种赋值导致的混乱
上一篇:学习笔记—Node中require的实现


下一篇:vue3 使用百度地图,踩坑日历