Node.js: `this` 运算符在模块作用域中使用时的上下文是什么?

Node.js: What is the context of the `this` operator when used in module scope?

代码

我写了下面的代码,保存为test.js:

var foo = 'I am local';
global.foo = 'I am global';

function print () {
     console.log(this.foo);
};

print(); 
console.log (this.foo); 

然后我 运行 在终端中使用命令 node test.js 它 returns:

I am global
undefined

问题

为什么不return:

I am global
I am global

?

Node.js中的所有脚本文件都在自己的执行上下文中执行,而浏览器在全局执行上下文中执行所有脚本文件。 在没有特定上下文的情况下调用函数时,通常会默认为全局 object in Node.

print(); //global execution context -> 'I am global'
console.log (this.foo); // no context -> undefined

函数的this属性在调用函数时设置,默认指向调用函数的对象,除非通过bind等方法设置值, applycall

值得注意的是,Node中的一个模块(相当于一个文件)被包裹在一个function()中,像这样:

NativeModule.wrapper = [
  ‘(function (exports, require, module, __filename, __dirname) { ‘,
  ‘\n});’
];

这意味着下面的所有代码片段实际上都是在这个包装函数中执行的。有关详细信息,请参阅 Where are vars stored in Nodejs

Console.log(this) 在函数内部

以下代码:

var apple = ‘red’;          // private variable in the wrapper function 
global.apple = ‘yellow’;    // property on the global object 

var foo = function () {

    var apple = ‘green’;
    console.log (this.apple);
}

foo();

returns yellow 因为内部函数无法访问任何外部函数的 this 值,对于此类内部函数,这是 this 的标准行为默认为全局对象(浏览器中的 window 对象)。

Console.log(this) 在一个对象中

以下代码:

var apple = ‘red’;          // private variable in the wrapper function
global.apple = ‘yellow’;    // property on the global object 

var myObject = {

    orange: ‘orange’,
    print: function () {

    console.log (this.orange);
    console.log (this.melon);   
}}

myObject.print();

returns orangeundefined 因为它是 myObject 调用 print。它returns undefined相对于this.melon,因为myObject没有属性这个名字的瓜。

Console.log(this) 在模块范围内

console.log 命令是 Node 全局对象上的 属性 函数值,因此您会期望以下代码

global.apple = ‘yellow’;
global.console.apple = 'yellow';

console.log(this.apple);

到 return yellow 因为 console.log()global.console.log() 相同。这意味着 console.log() 被全局对象调用,因此您会期望 this 指向 global.appleglobal.console.apple。然而,全局对象上的一些函数实际上是在模块范围内执行的(参见 Global objects),在这个范围内,Node 的设计者选择将 this 的值设置为对象 exports],它作为参数传递给包装 Node 模块的函数。

上面的代码因此 returns undefined 因为 exports 没有名称为 apple 的 属性。

在 Node 模块中,this 按照设计引用模块的 exports 对象:

console.log(this === exports); // true

使 console.log(this.foo) 等同于 console.log(exports.foo).

换句话说,this 既不引用全局对象,局部变量也不会神奇地成为 exports 的属性。

因为 exports.foo 不存在,你得到 undefined