Nodejs 为什么这样写可以输出?
Nodejs 为什么这样写可以输出?
在Node.js中,require函数用于加载模块。当你使用require加载一个模块时,该模块的导出对象(即exports对象)会被返回。这正是为什么在app.js文件中打印require("./test.js")会得到{name: 222}的原因。
让我们详细分析一下两个不同的版本:
版本一:
// test.js
var a = {};
a = exports;
a.name = 222;
在这个版本中,首先创建了一个空对象a,然后将exports赋值给a。接着修改了a.name属性,使其值为222。由于a已经指向了exports,所以对a的任何修改都会反映到exports上。因此,当app.js通过require加载test.js时,返回的是包含name属性的对象{name: 222}。
版本二:
// test.js
var a = {};
a.name = 222;
a = exports;
在这个版本中,首先创建了一个空对象a,并设置了a.name为222。然后将exports赋值给a。然而,此时a已经被重新指向exports,之前设置的a.name = 222并不会影响到exports对象。因此,exports仍然是一个空对象,最终app.js中打印出的是{}。
示例代码:
app.js
console.log(require("./test.js"));
test.js (版本一)
var a = {};
a = exports;
a.name = 222;
test.js (版本二)
var a = {};
a.name = 222;
a = exports;
通过以上分析可以看出,关键在于a是否被正确地重新指向exports,以及在重新指向之前是否已经对a进行了修改。如果修改发生在重新指向之前,那么这些修改会被反映到exports对象上。
想了一下貌似明白了。 a = exports 这个时候a就等于exports了,因为exports = {}.所以a = {}; a.name 等于 exports.name;
module.exports 是系统建立的对象。 exports 指向 module.exports
你的理解是对的。
在这个例子中,require 模块系统如何处理 exports 是关键。让我们先看代码:
示例代码
app.js
console.log(require("./test.js"));
test.js
var a = {};
a = exports;
a.name = 222;
解释
在 Node.js 中,当你在一个模块文件(如 test.js)中修改 exports,实际上是在修改一个引用到对象的变量。Node.js 的 require 系统会将这个对象作为模块的返回值。
第一种情况
在 test.js 中,首先定义了一个空对象 a,然后将 exports 赋值给 a。接着修改 a 对象的属性 name。
var a = {};
a = exports; // 将 `exports` 赋值给 `a`
a.name = 222; // 修改 `a` 的属性 `name`
此时,a 和 exports 指向同一个对象。因此,当你在 app.js 中使用 require("./test.js") 时,你会得到一个包含 name 属性的对象 { name: 222 }。
第二种情况
如果你将顺序反转,先修改 a 的属性 name,然后再将 exports 赋值给 a:
var a = {};
a.name = 222; // 修改 `a` 的属性 `name`
a = exports; // 将 `exports` 赋值给 `a`
在这种情况下,a 最终只指向 exports,而不会保留之前对 a 的任何修改。因此,当你在 app.js 中使用 require("./test.js") 时,你会得到一个空对象 {},因为 exports 在初始化时是空对象。
总结
关键在于理解 JavaScript 中的引用传递机制。在这个例子中,a 只是一个临时变量,用于操作最终会被赋值给 exports 的对象。

