我知道如何解决这个特定问题,但我想知道为什么会发生这种情况。基本上,当我尝试调用这样的函数时:
(callFoo ? this.foo : this.bar)();
它调用了正确的 foo 函数,但在 foo 内部,this
是全局窗口对象,而不是我期望的对象。
我希望这做同样的事情,但它没有:
(this.foo)();
上面的代码调用正确的函数并保持正确的上下文(this
是我所期望的)。
这是一个 jsfiddle 供您玩
。有人可以解释一下发生了什么吗?我了解如何解决这个问题(我什至不是该语法的粉丝),但我仍然想知道如果您从三元运算符返回函数,为什么this
会成为窗口。
编辑
我想完善我的问题: 这对我来说是有道理的:
(callFoo ? this.foo : this.bar)();
相当于:
var f = (callFoo ? this.foo : this.bar);
f();
对我来说,为什么this
成为该功能中的窗口是有道理的。
为什么这里没有发生同样的事情:
(this.foo)();
要获得正确的上下文调用对象,请像
this[ callFoo ? 'foo' : 'bar' ]();
this
的值始终取决于您调用函数的方式。你基本上是在调用函数,就像
fnc();
这导致this
始终是全局/窗口(在非严格模式下)。您需要调用该函数作为方法/属性,例如this.fnc()
。在这种情况下,默认情况下,this
将引用调用对象。
差异的原因:
var obj = new (function MyConstructor(){
this.getConstructor = function(){ return this.constructor.name; }
});
当操作数由任何运算符操作时,结果的工作方式与函数的返回值非常相似。传递的对象方法不再被视为绑定到对象。
(function(){ return obj.getConstructor; })(); //'Window'
但是,如果括号内除了属性访问之外什么都没有发生,则简单地忽略括号,而不是将其本身视为运算符。所以:
(obj.getConstructor)(); //'MyConstructor'
实际上只是相当于:
obj.getConstructor();
但是添加任何类型的有效操作,从而生成该方法:
(false || obj.getConstructor)(); //'Window'
obj.getConstructor 被视为已传递的方法,而不是通过"."关联绑定到对象的方法。
此表达式在逻辑上等效于以下内容:
var tempFun;
if(callFoo) {
tempFun = this.foo;
} else {
tempFun = this.bar;
}
tempFun();
这是失去this
参考的经典例子。正如您所说,您知道解决方法/解决方案:
tempFun.call(this);
或:
(callFoo ? this.foo : this.bar).call(this)
使用三元运算符时,需要在两个函数之间进行选择。 这类似于执行以下操作:
var func = this.foo;
foo(); // Inside this call, "this" will now refer to the global context
// -- "window" in a browser environment
这个(即"这个")是JavaScript中最大的棘手问题之一,关于它已经写了很多。
令人惊讶的是,当您在"this.foo"周围放置括号时,问题也不会发生。 但这不是你的问题:-)