module.exports和exports

2022-02-17  本文已影响0人  PoWerfulHeart

两者的关系

exports = module.exports = {}

nodejs如何导出模块

当不改变module.exports和exports的指向,module.exports和exports均可导出,因为上面也说过这两个对象实际上指向的都是同一个堆地址

不改变指向

  //a.js
  exports.a = 1;
  module.exports.b = 2;
  
  //b.js
  const test = require('./a');
  console.log(test);
  //output: { a: 1, b: 2 }

改变指向:仅module.exports可导出

  //a.js
  exports.a = 1;   // exports = { a: 1 };
  module.exports = { b: 2 };
  
  //b.js
  const test = require('./a');
  console.log(test);
  //output: { b: 2 }

刨根问底

为什么指向一旦被改变exports就不能导出对象了呢?

首先node加载模块的时候会用一个函数将代码包裹

  (function (exports, require, module, __filename, __dirname) {
  });

当加载模块的时候,module已经被当作参数传入,所以即使module.exports的值改变也能够在其他文件中进行调用,也就是为什么指向一旦被改变,只有module.exports可导出。
那么有同学问了exports也被当作参数传入啦~~~

另外node(commonjs)加载模块时,其实是进行的一个浅拷贝(基本类型一样,引用类型拷贝地址),所以单独改变模块里面的变量值(非引用类型),并不会影响导入的值,而es6的import则是创建一个动态的只读引用,等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。

利用node-inspector调试我们可以找到答案

  Module.prototype._compile = function(content, filename) {
  ......
  let result;
  //这里传入的exports其实是this.exports,而当前this是指向module的,所以加载模块传入的exports其实是module.exports,所以一旦改变了exports指向,就不能通过exports导出了
  const exports = this.exports;
  const thisValue = exports;
  const module = this;
  if (requireDepth === 0) statCache = new SafeMap();
  if (inspectorWrapper) {
    result = inspectorWrapper(compiledWrapper, thisValue, exports,
                              require, module, filename, dirname);
  } else {
    result = ReflectApply(compiledWrapper, thisValue,
                          [exports, require, module, filename, dirname]);
  }
  hasLoadedAnyUserCJSModule = true;
  if (requireDepth === 0) statCache = null;
  return result;
};
上一篇下一篇

猜你喜欢

热点阅读