首页 > 解决方案 > JavaScript Bind (this) 不访问类

问题描述

如果不对类本身进行一些修改,我无法访问类的方法。

请参阅以下演示代码:

function myCallback() {
  this.otherMethod();
}

class hiddenClass {

  static hiddenFunction(callback) {
    callback();
  }
  
  static otherMethod(){
    console.log("success");
  }
}

hiddenClass.hiddenFunction(myCallback);

在这个简单的示例中,我想在回调中访问 this.otherMethod()。显而易见的答案是更改callback()callback.bind(this)(),但是在这种情况下, hiddenClass 将是一个库。

我怎么能调用这个其他方法?

作为参考,我正在尝试使用 node-cron 创建 cron 作业。如果数据库检查返回 true,我想销毁这些作业,检查作业的每个周期(在回调中)。作业有一个内部方法.destroy()。我知道我可以将 cron 作业保存在一个变量中,然后调用variable.destroy(),但是有没有办法在回调中执行它(因为这些作业是在 for 循环中创建的,我不想确定要从中销毁哪个作业在回调中)

cron.schedule(`5 * * * * *`, async function () {
  schedule = await Schedule.findById(schedule._id);
  if (!schedule) this.destroy() // Destroy the job if schedule is not found (this returns Window)
}

);

标签: javascriptcallbacknode-cron

解决方案


您的推理是合理的,您需要将回调绑定到相关类。但是,可以通过修改对 hiddenFunction 的调用在您的示例代码中完成:

hiddenClass.hiddenFunction(myCallback.bind(hiddenClass));

这不需要修改库。


至于您的参考代码...

ES2015 之前的做法是创建匿名函数,通过调用当前循环迭代的值来绑定,举个简单的例子:

var schedules = [1,2,3,4,5];
for(var i=0;i<schedules.length;i++){
  setTimeout(function(){console.log(schedules[i])}, 10);
}
/* => outputs:
5
5
5
5
5
*/
for(var i=0;i<schedules.length;i++){
  // create an anonymous function with the first arg bound at call time
  (function(j){
    setTimeout(function(){console.log(schedules[j])}, 10);
  }(i));
}
/* => outputs:
1
2
3
4
5
*/

但是,这在您的代码中是不可能的,因为您试图传递匿名回调并在所述函数中引用当前循环的迭代值,这要求匿名函数在将cron.schedule自身传递给cron.schedule.

该问题的解决方案是在循环中使用letconst绑定当前迭代的值。它们是块范围的,而不是词法范围的,因此它们在每次迭代时保留值,从而导致同一个匿名函数的 N 个闭包。我们可以在以下循环中演示两者之间的区别:

for(var foo of [1,2,3,4,5]){
  const bar = foo;
  (async function(){
    await Promise.resolve().then(()=>console.log({bar, foo}));
  }());
}

/* outputs:
{ bar: 1, foo: 5 }
{ bar: 2, foo: 5 }
{ bar: 3, foo: 5 }
{ bar: 4, foo: 5 }
{ bar: 5, foo: 5 }
*/

将它们结合在一起,您的循环调度程序将如下所示:

for(let schedule of schedules){
  const me = cron.schedule(`5 * * * * *`, async function () {
    // the value of `me` is bound to each iteration and you can refer to it as needed
    schedule = await Schedule.findById(schedule._id);
    if (!schedule) me.destroy();
  });
}

推荐阅读