通常将上下文应用于方法别名

时间:2019-06-18 09:58:08

标签: javascript ecmascript-6

我遇到一个我无法解决的问题。我不知道这是缺乏知识还是Java语言中甚至不可能做到这一点,但我希望了解这一点。

我试图在对象中执行功能别名列表。在执行这些功能时,我想像直接从实例本身执行它们一样使用它们,因此我可以在该调用的方法中使用其他方法和实例变量。为了使我的解释更加清楚,这是一个示例:

class Bar {
  constructor() {
    this.name = "Bar";
  }
    
  someMethod() {
    console.log(this.name) // should log Bar
  }
}

class Foo {
  constructor() {
    this.name = "Foo";
  }

  someOtherMethod() {
    console.log(this.name) // should log Foo
  }
}

const bar = new Bar();
const foo = new Foo();


const methodList = {
  foo: bar.someMethod,
  baz: foo.someOtherMethod,
}

for(let prop in methodList) {
  methodList[prop](); // logs 2x undefined
}

for(let prop in methodList) {
  methodList[prop].apply(foo); //logs 2x Foo
}

从上面的示例中可以看出,this.name是类实例中的变量。执行第二个循环时,将按预期应用上下文并正确记录日志。我想看到该上下文是自动应用的,因为函数别名对象是在另一个文件中执行的,不知道foobar而是仅接收列表。

有什么办法可以做到这一点?

2 个答案:

答案 0 :(得分:2)

您可以将foobar方法包装在它们自己的函数中。在这些方法中,您可以像下面这样在对象上调用对象的方法someMethod() / someOtherMethod()

const methodList = {
  foo: (...args) => bar.someMethod(...args),
  baz: (...args) => foo.someOtherMethod(...args),
}

当前,您的第一个循环不起作用,因为您的this并未引用对象的实际上下文,因为这不是用于调用该方法的内容。相反,它指的是您的methodList

请参见下面的示例:

class Bar {
  constructor() {
    this.name = "Bar";
  }
    
  someMethod() {
    console.log(this.name) // should log Bar
  }
}

class Foo {
  constructor() {
    this.name = "Foo";
  }

  someOtherMethod() {
    console.log(this.name) // should log Foo
  }
}

const bar = new Bar();
const foo = new Foo();


const methodList = {
  foo: (...args) => bar.someMethod(...args),
  baz: (...args) => foo.someOtherMethod(...args),
}

for(let prop in methodList) {
  methodList[prop](); // correct logs
}

答案 1 :(得分:1)

之所以会这样,是因为调用this时上下文methodList[prop]  是methodList,因此this中的someMethodsomeOtherMethod实际上是:

{
  foo: bar.someMethod,
  baz: foo.someOtherMethod,
}

要解决此问题,您可以将方法包装在返回调用的方法的匿名函数中,如下所示:

class Bar {
  constructor() {
    this.name = "Bar";
  }
    
  someMethod(a,b,c) {
    console.log(a,b,c,this.name) // should log Bar
  }
}

class Foo {
  constructor() {
    this.name = "Foo";
  }

  someOtherMethod(a,b,c) {
    console.log(a,b,c,this.name) // should log Foo
  }
}

const bar = new Bar();
const foo = new Foo();


const methodList = {
  foo: (...args) => bar.someMethod(...args), // <-- anonymous function that, once invoked, returns `bar.someMethod()`, hence the contextual `this` of someMethod will be `bar`.
  baz: function() {  // <-- same as above, just written without the lambda notation.
     return foo.someOtherMethod(...arguments);
  }//^
}//  | <-- that evaluation is actually calling the above code block.
//   |-------------------------------------|
for(let prop in methodList) {//            |
  methodList[prop](1,4,'hello'); // <------|
}