Node.js模块中exports与require返回对象的关联疑问
先看你给出的模块代码:
mymodule.js
exports.bar = "Hello"; exports.foo = function(){ console.log(exports.bar); }
app.js
var baz = require("./mymodule.js"); baz.foo(); //控制台输出"Hello"
你的疑问是:调用baz.foo()时控制台输出了"Hello",但foo函数里打印的是exports.bar而非baz.bar,想知道Node.js是自动做了关联转换,还是exports对象仍独立存在?
我来给你掰扯清楚这个逻辑:
其实Node.js里每个模块都有自己独立的作用域,当模块被加载时,Node会自动给这个模块创建几个关键变量:
module:代表当前模块的对象,它的exports属性是模块对外暴露的接口exports:一开始就是module.exports的引用(相当于模块内部默认执行了var exports = module.exports;)
当你在mymodule.js里给exports.bar和exports.foo赋值时,本质上是在给module.exports这个对象添加属性——因为此时exports和module.exports指向同一个内存地址的对象。
而当你在app.js里用require引入模块时,require函数返回的就是这个模块的module.exports对象的引用,也就是你代码里的baz。
所以回到你的问题:foo函数里的exports.bar和baz.bar其实是同一个东西!因为:
baz是module.exports的引用- 模块内部的
exports一开始也是module.exports的引用 - 你只是给这个共享的对象添加了属性,没有改变
exports的指向
举个反例帮你理解边界情况:要是你在mymodule.js里写了exports = { bar: "Hi" },这时候exports就和module.exports断开了关联(因为你给exports重新赋值了一个新对象),这时候baz.bar还是原来的"Hello",而foo函数里的exports.bar会是"Hi"——不过这种情况在你的代码里并没有发生。
总结一下:你的代码里exports和baz(也就是module.exports)指向的是同一个对象,不存在什么“自动转换”,只是它们本来就是同一个东西的不同引用而已。
内容的提问来源于stack exchange,提问作者gldanoob

