node.js:在全局范围中混淆使用'this'

时间:2012-02-28 15:29:38

标签: javascript node.js

我最近一直在玩node.js而且我遇到了一个关于模块全局范围内this的使用的奇怪行为。

this绑定到全局范围中的module.exports:

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

但是this在方法范围内绑定到全局:

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

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

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

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

我想解决方案是永远不要在全局范围内使用this并明确使用extendsglobal,但是这背后有一个逻辑还是一个bug或node.js中的限制?

3 个答案:

答案 0 :(得分:7)

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

在你的情况下,你有一个自动执行的匿名函数,this总是引用全局对象(非严格模式)或undefined(ES5严格)。

如果要访问“外部”this值,可以在执行该函数之前存储引用,例如

var outerScope = this;

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

或重新.bind()自己的功能范围,如

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

答案 1 :(得分:1)

在处理一个简单的CommonJS模块实现时,我不得不考虑在模块的全局范围内如何处理this;规范没有解决这个问题。

我最初也将其设置为exports对象,因为我认为这会有用,但后来found some code我需要“模块化”使用this来获取这是全局对象的句柄,因此我将this更改回全局对象,以便为模块代码提供尽可能“正常”的环境。

我们只能猜测为什么节点的设置方式(或询问作者),但我的猜测只是因为它似乎是一个有用的想法,类似于你可以给{{{ 1}}在节点中对象module属性并将其反映在模块的实际exports中(此行为也不是规范的一部分,但也不违反它)。

关于exports在函数中引用this的问题部分,正如其他答案所解释的那样,这就是global的工作方式;它不是特定于节点的行为,它是一种奇怪的javascript行为。

答案 2 :(得分:1)

我不知道这是否是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

正如您所看到的,在不指定其上下文的情况下执行方法会将上下文设置为全局上下文。在这种情况下是DOMWindow对象。

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