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

Javascript 从三元运算符返回的函数中丢失上下文,javascript,ternary-operator,Javascript,Ternary Operator,我知道如何避开这个特殊的问题,但我想知道为什么会发生这种情况。基本上,当我尝试调用这样的函数时: (callFoo ? this.foo : this.bar)(); var tempFun; if(callFoo) { tempFun = this.foo; } else { tempFun = this.bar; } tempFun(); 它调用正确的foo函数,但在foo内部,这是全局窗口对象,而不是我期望的对象 我希望这也能起到同样的作用,但事实并非如此: (this

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

(callFoo ? this.foo : this.bar)();
var tempFun;
if(callFoo) {
    tempFun = this.foo;
} else {
    tempFun = this.bar;
}
tempFun();
它调用正确的foo函数,但在foo内部,这是全局窗口对象,而不是我期望的对象

我希望这也能起到同样的作用,但事实并非如此:

(this.foo)();
上面的代码调用了正确的函数并维护了正确的上下文,这就是我所期望的

有人能解释一下发生了什么事吗?我知道如何解决这个问题,我甚至不喜欢这种语法,但我仍然想知道,如果你从三元运算符返回一个函数,为什么它会变成一个窗口

编辑 我想进一步完善我的问题: 这对我来说很有意义:

(callFoo ? this.foo : this.bar)();
相当于:

var f = (callFoo ? this.foo : this.bar);
f();
obj.getConstructor();
这对我来说很有意义,为什么它会成为函数中的窗口

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

(this.foo)();

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

this[ callFoo ? 'foo' : 'bar' ]();
它的值始终取决于调用函数的方式。你基本上是在调用函数,就像

fnc();

这会导致在非严格模式下始终为全局/窗口。您需要像this.fnc这样以方法/属性的形式调用函数。在这种情况下,默认情况下,这将引用调用对象。

要获得正确的上下文调用对象,请按如下方式调用它

this[ callFoo ? 'foo' : 'bar' ]();
它的值始终取决于调用函数的方式。你基本上是在调用函数,就像

fnc();

这会导致在非严格模式下始终为全局/窗口。您需要像this.fnc这样以方法/属性的形式调用函数。在这种情况下,默认情况下,这将引用调用对象。

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

var func = this.foo;
foo(); // Inside this call, "this" will now refer to the global context
       // -- "window" in a browser environment
这是JavaScript中最棘手的事情之一,已经有很多关于它的文章


令人惊讶的是,当您在this.foo周围使用paren时,问题并没有出现。但这不是你的问题:-

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

var func = this.foo;
foo(); // Inside this call, "this" will now refer to the global context
       // -- "window" in a browser environment
这是JavaScript中最棘手的事情之一,已经有很多关于它的文章


令人惊讶的是,当您在this.foo周围使用paren时,问题并没有出现。但这不是你的问题:-

这个表达式在逻辑上等同于这样的东西:

(callFoo ? this.foo : this.bar)();
var tempFun;
if(callFoo) {
    tempFun = this.foo;
} else {
    tempFun = this.bar;
}
tempFun();
这是一个经典的例子。正如您所说,您知道解决方案:

tempFun.call(this);
或:


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

(callFoo ? this.foo : this.bar)();
var tempFun;
if(callFoo) {
    tempFun = this.foo;
} else {
    tempFun = this.bar;
}
tempFun();
这是一个经典的例子。正如您所说,您知道解决方案:

tempFun.call(this);
或:


产生差异的原因:

var obj = new (function MyConstructor(){
    this.getConstructor = function(){ return this.constructor.name; }
});
当操作数由任何运算符操作时,结果的工作方式与函数的返回值非常相似。传递的对象方法不再被视为绑定到对象

(function(){ return obj.getConstructor; })(); //'Window'
但是,如果paren内部除了属性访问之外什么都没有发生,那么paren将被忽略,而不是被视为操作符本身。因此:

(obj.getConstructor)(); //'MyConstructor'
实际上相当于:

var f = (callFoo ? this.foo : this.bar);
f();
obj.getConstructor();
但添加任何类型的有效操作,以生成该方法:

(false || obj.getConstructor)(); //'Window'

并且obj.getConstructor被视为已传递的方法,而不是通过“.”关联绑定到对象的方法。

差异原因:

var obj = new (function MyConstructor(){
    this.getConstructor = function(){ return this.constructor.name; }
});
当操作数由任何运算符操作时,结果的工作方式与函数的返回值非常相似。传递的对象方法不再被视为绑定到对象

(function(){ return obj.getConstructor; })(); //'Window'
但是,如果paren内部除了属性访问之外什么都没有发生,那么paren将被忽略,而不是被视为操作符本身。因此:

(obj.getConstructor)(); //'MyConstructor'
实际上相当于:

var f = (callFoo ? this.foo : this.bar);
f();
obj.getConstructor();
但添加任何类型的有效操作,以生成该方法:

(false || obj.getConstructor)(); //'Window'

obj.getConstructor被视为一个已传递的方法,而不是通过“.”关联绑定到对象的方法。

我喜欢您将其分解为实际if-else的方式。这肯定有助于澄清问题。有没有解释为什么这件事不会发生。福?我喜欢你把它变成实际的if-else。这肯定有助于澄清问题。关于为什么这件事不会发生的任何解释。foo?谢谢你的回答-我喜欢与fnc的比较,因为它清楚地表明,上下文将丢失。正如我所说,我知道如何避开它,但我更好奇的是,为什么叫callFoo?this.foo:this.bar与this.foo不同。这是不是只是没有对.foo进行评估?让它和这个一模一样。foo?谢谢你的回答-我喜欢与fnc的比较,因为它非常清楚地表明上下文将丢失。正如我所说,我是联合国会员国
我知道怎么绕过它,但我更好奇的是为什么叫callFoo?this.foo:this.bar与this.foo不同。这是不是只是没有对.foo进行评估?和这个一模一样。福?正是我想要的。非常感谢。感谢您更正+obj.getConstructor位。我试着想一些类似的东西,但我不能。是的,我不应该仅仅因为它与一个非函数一起工作就认为这是可行的。一个奇怪的现象是,本机对象方法不一定遵循相同的行为,即使它们的行为好像在以其他方式使用“this”。这正是我想要的。非常感谢。感谢您更正+obj.getConstructor位。我试着想一些类似的东西,但我不能。是的,我不应该仅仅因为它与一个非函数一起工作就认为这是可行的。一个奇怪的现象是,本机对象方法不一定遵循相同的行为,即使它们的行为好像在以其他方式使用“this”。