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

时间:2012-10-04 21:21:02

标签: javascript ternary-operator

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

(callFoo ? this.foo : this.bar)();

它调用了正确的foo函数,但在foo中,this是全局的window对象而不是我期望的对象。

我希望这会做同样的事情,但事实并非如此:

(this.foo)();

上面的代码调用了正确的函数并维护了正确的上下文(this就是我所期望的那样)。

Here is a jsfiddle for you to play around with.

有人可以解释一下发生了什么吗?我理解如何解决这个问题(我甚至不是那种语法的粉丝),但是如果从三元运算符返回一个函数,我仍然想知道为什么this成为窗口。


修改
我想改进我的问题: 对我来说这是有意义的:

(callFoo ? this.foo : this.bar)();

相当于:

var f = (callFoo ? this.foo : this.bar);
f();

对我来说,this成为该函数中的窗口是有道理的。

为什么不会发生同样的事情:

(this.foo)();

4 个答案:

答案 0 :(得分:2)

要拥有正确的上下文调用对象,请将其命名为

this[ callFoo ? 'foo' : 'bar' ]();

this的值始终取决于您调用函数的 。你基本上就像调用

一样调用函数
fnc();

导致this始终为全局 / 窗口(在非严格模式下)。您需要将此函数作为方法 / 属性调用,如this.fnc()。在这种情况下,this将默认引用调用对象。

答案 1 :(得分:1)

此表达式在逻辑上等同于以下内容:

var tempFun;
if(callFoo) {
    tempFun = this.foo;
} else {
    tempFun = this.bar;
}
tempFun();

这是丢失this引用的经典示例。如你所说,你知道解决方法/解决方案:

tempFun.call(this);

或:

(callFoo ? this.foo : this.bar).call(this)

答案 2 :(得分:1)

出现差异的原因:

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被视为已传递的方法,而不是通过'。'绑定到对象的方法。关联。

答案 3 :(得分:0)

使用三元运算符时,您要在两个函数之间进行选择。这与执行以下操作类似:

var func = this.foo;
foo(); // Inside this call, "this" will now refer to the global context
       // -- "window" in a browser environment

这个(即“this”)是JavaScript中最棘手的事情之一,并且已经写了很多。

当您在“this.foo”周围抛出问题时,问题也不会发生,这有点令人惊讶。但这不是你的问题: - )