Nodejs 为什么这样写可以输出?

Nodejs 为什么这样写可以输出?

app.js

console.log(require("./test.js"));

test.js

var a = {}; a = exports; a.name = 222;

结果-> {name:222}

为什么会打印出a的结果。

如果改成 var a = {}; a.name = 222; a = exports;

结果 -> {}


4 回复

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`

此时,aexports 指向同一个对象。因此,当你在 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 的对象。

回到顶部