节点。js:在全局范围内使用“this”让人困惑

时间:2022-08-26 11:24:23

I've been toying with node.js lately and I ran into a weird behavior about the usage of this in the global scope of a module.

我一直在玩弄node。最近,我和js遇到了一个奇怪的问题,即在模块的全局范围内使用这个函数。

this is bound to module.exports in the global scope:

它绑定到模块。全球范围内的出口:

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

But this is bound to global in a method scope:

但在方法范围内,这是绑定到全局的:

(function() { console.log(this === global); })(); // -> true

This also lead to this confusing behavior:

这也导致了这种令人困惑的行为:

this.Foo = "Weird";
console.log(Foo); // -> throws undefined

(function() { this.Bar = "Weird"; })();
console.log(Bar); // -> "Weird"

I guess that the solution is to never use this in the global scope and explicitly use extends or global instead, but is there a logic behind all this or is it a bug or limitation in node.js?

我想解决方案是永远不要在全局范围中使用这个,而是显式地使用扩展或全局,但这一切背后是否有逻辑,还是node.js中的bug或限制?

3 个解决方案

#1


1  

In working on a simple CommonJS modules implementation, I had to think about what to do with this in the global scope of the module; it's not addressed by the spec.

在处理一个简单的CommonJS模块实现时,我必须考虑如何在模块的全局范围内处理这个问题;规范中没有提到。

I also set it up as the exports object at first, because I thought that would be useful, but later found some code I needed to "modulize" that was using this to get a handle to the global object, so I changed this back to the global object to provide as close of an environment to "normal" as possible for module code.

我也设置它为出口对象,因为我认为这将是有用的,但后来发现一些代码我需要“modulize”是使用这个处理全局对象,所以我改变了这个回到全局对象提供接近环境尽可能地“正常”的模块代码。

We can only guess at why node is set up the way it is (or ask the author), but my guess is it was done simply because it seemed like a useful idea, similar to the way you can give the module object an exports property in node and have it reflected in the module's actual exports (this behavior also isn't part of the spec, but doesn't go against it either).

我们只能猜测为什么节点设置方式(或者问作者),但我猜它是,因为它似乎是一个有用的概念,类似于你可以给出口模块对象的一个属性节点,它反映在模块的实际出口(这种行为还不规范的一部分,但并不违背它)。

As for the part of your question about this referencing global in functions, as the other answers explain, that's just the way this works; it's not a node-specific behavior, it's a weird javascript behavior.

至于你的问题的一部分关于这个引用的全局函数,就像其他答案解释的那样,这就是它的工作原理;它不是一个特定于节点的行为,而是一个奇怪的javascript行为。

#2


7  

The "logic" behind that is, that the value of this always depends on how a function is invoked.

它背后的“逻辑”是,它的值总是取决于如何调用函数。

In your case, you have a self-executing anonymous function, there, this always references the global object (non strict mode) or undefined (ES5 strict).

在您的例子中,您有一个自执行的匿名函数,它总是引用全局对象(非严格模式)或未定义的对象(ES5 strict)。

If you want to access the "outer" this value, you could either store a reference before executing that function, like

如果您想访问“外部”这个值,您可以在执行该函数之前存储一个引用,比如

var outerScope = this;

(function() { outerScope.Bar = "Weird"; })();
console.log(Foo); // -> throws undefined

or re- .bind() the functions scope yourself, like

或re .bind()函数可以自己确定范围,比如

(function() { this.Bar = "Weird"; }).bind(this)();

#3


1  

I don't know if this is the exact intention of Node.js team, but I would be surprised if it was not. Consider this example ran in the dev console of a browser (e.g. chrome):

我不知道这是不是Node的真正意图。js团队,但如果不是,我会很惊讶。请考虑在浏览器的开发控制台中运行的这个示例(例如chrome):

var x = function(){console.log(this)}
a = {}
a.x = x
a.xx = function(){x()}

a.x()
>> Object
a.xx()
>> DOMWindow
x()
>> DOMWindow

As you can see executing a method without specifying its context sets the context to be the global one. In this case the DOMWindow object.

正如您所看到的,执行一个方法而不指定其上下文将上下文设置为全局上下文。在本例中是DOMWindow对象。

When you are inside a module your context is the module, but executing a method in it without specifying a context with .call or .apply or obj. will use the global context, global, instead of the local one, module.exports.

当您在模块中时,您的上下文就是模块,但是在其中执行一个方法时,不需要使用.call或.apply或obj指定上下文。将使用全局上下文,全局上下文,而不是本地上下文。

#1


1  

In working on a simple CommonJS modules implementation, I had to think about what to do with this in the global scope of the module; it's not addressed by the spec.

在处理一个简单的CommonJS模块实现时,我必须考虑如何在模块的全局范围内处理这个问题;规范中没有提到。

I also set it up as the exports object at first, because I thought that would be useful, but later found some code I needed to "modulize" that was using this to get a handle to the global object, so I changed this back to the global object to provide as close of an environment to "normal" as possible for module code.

我也设置它为出口对象,因为我认为这将是有用的,但后来发现一些代码我需要“modulize”是使用这个处理全局对象,所以我改变了这个回到全局对象提供接近环境尽可能地“正常”的模块代码。

We can only guess at why node is set up the way it is (or ask the author), but my guess is it was done simply because it seemed like a useful idea, similar to the way you can give the module object an exports property in node and have it reflected in the module's actual exports (this behavior also isn't part of the spec, but doesn't go against it either).

我们只能猜测为什么节点设置方式(或者问作者),但我猜它是,因为它似乎是一个有用的概念,类似于你可以给出口模块对象的一个属性节点,它反映在模块的实际出口(这种行为还不规范的一部分,但并不违背它)。

As for the part of your question about this referencing global in functions, as the other answers explain, that's just the way this works; it's not a node-specific behavior, it's a weird javascript behavior.

至于你的问题的一部分关于这个引用的全局函数,就像其他答案解释的那样,这就是它的工作原理;它不是一个特定于节点的行为,而是一个奇怪的javascript行为。

#2


7  

The "logic" behind that is, that the value of this always depends on how a function is invoked.

它背后的“逻辑”是,它的值总是取决于如何调用函数。

In your case, you have a self-executing anonymous function, there, this always references the global object (non strict mode) or undefined (ES5 strict).

在您的例子中,您有一个自执行的匿名函数,它总是引用全局对象(非严格模式)或未定义的对象(ES5 strict)。

If you want to access the "outer" this value, you could either store a reference before executing that function, like

如果您想访问“外部”这个值,您可以在执行该函数之前存储一个引用,比如

var outerScope = this;

(function() { outerScope.Bar = "Weird"; })();
console.log(Foo); // -> throws undefined

or re- .bind() the functions scope yourself, like

或re .bind()函数可以自己确定范围,比如

(function() { this.Bar = "Weird"; }).bind(this)();

#3


1  

I don't know if this is the exact intention of Node.js team, but I would be surprised if it was not. Consider this example ran in the dev console of a browser (e.g. chrome):

我不知道这是不是Node的真正意图。js团队,但如果不是,我会很惊讶。请考虑在浏览器的开发控制台中运行的这个示例(例如chrome):

var x = function(){console.log(this)}
a = {}
a.x = x
a.xx = function(){x()}

a.x()
>> Object
a.xx()
>> DOMWindow
x()
>> DOMWindow

As you can see executing a method without specifying its context sets the context to be the global one. In this case the DOMWindow object.

正如您所看到的,执行一个方法而不指定其上下文将上下文设置为全局上下文。在本例中是DOMWindow对象。

When you are inside a module your context is the module, but executing a method in it without specifying a context with .call or .apply or obj. will use the global context, global, instead of the local one, module.exports.

当您在模块中时,您的上下文就是模块,但是在其中执行一个方法时,不需要使用.call或.apply或obj指定上下文。将使用全局上下文,全局上下文,而不是本地上下文。