首页 > 解决方案 > 当从三元运算符返回时,方法如何变得未绑定?

问题描述

class TestClass {
    constructor() {
        this.prop = 5;
    }
    MethA() {
        console.log(this);
        console.log(this.prop);
    }
    MethB() {
        (true ? this.MethA : null)();
    }
}
Test = new TestClass();
Test.MethB();

为什么从三元运算符 in(this.prop)到达时此代码会失败?MethAMethB

VM:6 undefined
VM:7 Uncaught TypeError: Cannot read property 'prop' of undefined
    at MethA (<anonymous>:7:26)
    at TestClass.MethB (<anonymous>:10:35)
    at <anonymous>:14:6

null抢占任何关于显然是示范性示例的进一步评论:

在真实代码中,三元运算符的条件是变量标志,假值是另一种方法。这种结构的好处是两个函数可以共享一个参数列表,该列表只需要编写一次并且不需要名称。

不,将调用移到三元运算符内部并不能回答这个问题。它失去了只需要编写一次参数的好处,而且它也是副作用滥用。

真正的解决方案是用if {} else {}for 副作用替换三元,或者将方法包装在箭头函数中以获得值表达式。但这也不能回答这个问题:关键不是什么代码可以达到类似的结果,因为那很容易;关键是为什么这段代码不起作用,以及潜在的语言怪癖是什么原因造成的。

标签: javascript

解决方案


它与作用域在 JavaScript 中的工作方式有关,特别是值的this绑定方式。

要理解的主要事情是(通常)当您调用一个函数时,this设置为调用该方法的对象

wookie.eatBanana(); // inside the eatBanana method, this === wookie

但是,如果您与对象分开调用该方法,则this最终会是undefined

const detachedFn = wookie.eatBanana;

// same function, but now this === undefined
detachedFn(); 

而你this.MethA在三元中所做的事情有效地将它与“这个”分开。它有效地做到了这一点:

MethB() {
  const method = true ? this.MethA : null;
  method(); // invoked standalone, so "this" is undefined inside MethA.
}

如果这不是所需的行为,则有多种方法可以解决此问题。

箭头函数继承了当前作用域,因此如果将 MethA 更改为箭头函数,您会注意到此问题消失了:

MethA = () => {
  console.log(this);
  console.log(this.prop);
}

const method = this.MethA;
method(); // this is fine, because arrow functions are bound to the scope in which they are declared

或者您可以使用bindcallapply明确指定范围:

const method = this.MethA.bind(this); // new function pre-bound to 'this'
MethA.call(this); // invoke with a specific scope
MethA.apply(this); // same as above; handles args a bit differently

推荐阅读