从三元运算符返回的函数中丢失上下文



我知道如何解决这个特定问题,但我想知道为什么会发生这种情况。基本上,当我尝试调用这样的函数时:

(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"周围放置括号时,问题也不会发生。 但这不是你的问题:-)

最新更新