node.js:将“this”的用法混淆在全局范围内
最近我一直在玩node.js,并且在模块的全局范围内遇到了一个奇怪的行为。
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"
我想解决scheme是从来没有在全球范围内使用this
,明确地使用extends
或global
相反,但有没有背后的逻辑,或者它是一个错误或在node.js限制?
在一个简单的CommonJS模块实现上,我不得不考虑在模块的全局范围内如何处理this
。 规范没有解决这个问题。
我也将它设置为exports
对象,因为我认为这将是有用的,但后来发现一些代码,我需要“模块化”,这是使用this
来获得一个句柄的全局对象,所以我改变了this
为模块代码尽可能提供“正常”环境的全局对象。
我们只能猜测为什么节点的设置方式(或问作者),但我的猜测是这样做的,因为它看起来像一个有用的想法,类似于你可以给module
对象的方式exports
属性在节点,并反映在模块的实际exports
(这种行为也不是规范的一部分,但也不会违背它)。
关于this
引用global
函数的问题的一部分,正如其他答案所解释的那样,这只是this
工作方式; 这不是一个特定于节点的行为,这是一个奇怪的JavaScript行为。
这背后的“逻辑”是,它的价值总是取决于函数是如何被调用的 。
在你的情况下,你有一个自我执行的匿名函数,在那里, this
总是引用全局对象(非严格模式)或undefined
(ES5严格)。
如果你想访问这个“外部” this
值,你可以在执行该函数之前存储一个引用,比如
var outerScope = this; (function() { outerScope.Bar = "Weird"; })(); console.log(Foo); // -> throws undefined
或重新.bind()
函数范围自己,像
(function() { this.Bar = "Weird"; }).bind(this)();
我不知道这是否是Node.js团队的确切意图,但如果不是,我会感到惊讶。 考虑这个例子在浏览器的开发控制台(例如chrome)中运行:
var x = function(){console.log(this)} a = {} ax = x a.xx = function(){x()} ax() >> Object a.xx() >> DOMWindow x() >> DOMWindow
正如你所看到的执行方法而不指定其上下文将上下文设置为全局上下文。 在这种情况下,DOMWindow对象。
当你在一个模块中时,你的上下文是模块,但是在它里面执行一个方法,而不用.call或者.apply或者obj指定一个上下文。 将使用全局上下文, global
,而不是本地的, module.exports
。