Node.js中看JavaScript的引用

2020-06-17 07:02:02易采站长站整理

为了理解这个比较拗口的结论,让我们来看一段代码:


var obj = { name: 'Alan' };
function test1(obj) {
obj = { hello: 'world' }; // 试图修改外部obj
}
test1(obj);
console.log(obj); // { name: 'Alan' } // 并没有修改①
function test2(obj) {
obj.name = 'world'; // 根据该对象修改其上的属性
}
test2(obj);
console.log(obj); // { name: 'world' } // 修改成功②

通过这个例子我们可以看到,data 虽然像一个引用一样指向了 obj.data,并且通过 data 可以访问到 obj.data 上的属性。但是由于 JavaScript 值传递的特性直接修改 data = xxx 并不会使得 obj.data = xxx。

打个比方最初设置 var data = obj.data 的时候,内存中的情况大概是:

|   Addr   |  内容  | |———-|——– | obj.data |  内存1 |
| data | 内存1 |

所以通过 data.xx 可以修改 obj.data 的内存1。

然后设置 data = xxx,由于 data 是拷贝的一个新的值,只是这个值是一个引用(指向内存1)罢了。让它等于另外一个对象就好比:

|   Addr   |  内容  | |———-|——– | obj.data |  内存1 |
| data | 内存2 |

让 data 指向了新的一块内存2。

如果是传统的引用(如上文中提到的 C++ 的引用),那么 obj.data 本身会变成新的内存2,但 JavaScript 中均是值传递,对象在传递的过程中拷贝了一份新的引用。所以这个新拷贝的变量被改变并不影响原本的对象。

Node.js 中的 module.exports 与 exports

上述例子中的 obj.data 与 data 的关系,就是 Node.js 中的 module.exports 与 exports 之间的关系。让我们来看看 Node.js 中 require 一个文件时的实际结构:


function require(...) {
var module = { exports: {} };
((module, exports) => { // Node.js 中文件外部其实被包了一层自执行的函数
// 这中间是你模块内部的代码.
function some_func() {};
exports = some_func;
// 这样赋值,exports便不再指向module.exports
// 而module.exports依旧是{}
module.exports = some_func;
// 这样设置才能修改到原本的exports
})(module, module.exports);
return module.exports;
}

所以很自然的:


console.log(module.exports === exports); // true
// 所以 exports 所操作的就是 module.exports

Node.js 中的 exports 就是拷贝的一份 module.exports 的引用。通过 exports 可以修改Node.js 当前文件导出的属性,但是不能修改当前模块本身。通过 module.exports 才可以修改到其本身。表现上来说: