JavaScript 绑定 (this) 而不访问 class

JavaScript Bind (this) without access to class

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

查看下面的演示代码:

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 作业。如果数据库检查 returns 为真,我想销毁这些作业,检查作业的每个周期(在回调中)。该作业有一个内部方法 .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)
}

);

您的推理是合理的,您需要将回调绑定到有问题的 class。但是,可以在您的示例代码中通过修改对 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
*/

但是,这在您的代码中是不可能的,因为您试图传递匿名回调并在所述函数中引用当前循环的迭代值,要求匿名函数知道 return 的值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();
  });
}