我最近一直在玩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
并明确使用extends
或global
,但是这背后有一个逻辑还是一个bug或node.js中的限制?
答案 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
。