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
.
之前
问题的解决方案是在循环中使用 let
或 const
来绑定当前迭代的值。它们是块作用域的,而不是词法作用域的,因此它们在每次迭代中保留值,导致同一匿名函数的 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();
});
}
如果不对 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
.
问题的解决方案是在循环中使用 let
或 const
来绑定当前迭代的值。它们是块作用域的,而不是词法作用域的,因此它们在每次迭代中保留值,导致同一匿名函数的 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();
});
}