【问题标题】:Losing context from function returned by ternary operator从三元运算符返回的函数中丢失上下文
【发布时间】:2012-10-04 21:21:02
【问题描述】:

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

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

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

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

(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)();

【问题讨论】:

    标签: javascript ternary-operator


    【解决方案1】:

    要获得正确的上下文调用对象,请像这样调用它

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

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

    fnc();
    

    导致this 始终为global / window(在非严格模式下)。您需要以 method / property 的形式调用该函数,例如 this.fnc()。在这种情况下,this 将默认引用调用的对象。

    【讨论】:

    • 感谢您的回答——我喜欢与fnc() 的比较,因为它清楚地表明上下文将会丢失。正如我所说,我知道如何绕过它,但我更好奇为什么(callFoo ? this.foo : this.bar)()(this.foo)() 不同。 (this.foo) 只是没有评估吗?使其与this.foo 相同?
    【解决方案2】:

    产生差异的原因:

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

    【讨论】:

    • 正是我想要的。谢谢你。感谢您更正(+obj.getConstructor)() 位。我一直在想这样的事情,但我想不出来。
    • 是的,我不应该仅仅因为它适用于匿名函数就认为它会起作用。一个奇怪的是,本地对象方法不一定遵循相同的行为,即使它们的行为就像以其他方式使用“this”一样。
    【解决方案3】:

    这个表达式在逻辑上等价于这样的:

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

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

    tempFun.call(this);
    

    或:

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

    【讨论】:

    • 我喜欢你如何将它分解为实际的 if-else。它肯定有助于澄清事情。关于为什么(this.foo)() 没有发生同样的事情的任何解释?
    【解决方案4】:

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

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

    this(即“this”)是 JavaScript 中最棘手的事情之一,关于它的文章很多。

    当你在“this.foo”周围加上括号时,这个问题并没有发生,这有点令人惊讶。但这不是你的问题:-)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-05-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-24
      • 2021-10-23
      • 2011-04-03
      • 1970-01-01
      相关资源
      最近更新 更多