Javascript class 成员函数通过 setInterval 调用成员函数,无法访问成员变量

Javascript class member function calling member function by setInterval, couldn't access member variable

我正在尝试使用带链表的 setInterval 创建一个简单的任务队列。 我用链表创建了一个 class,setInterval 函数将继续调用一个成员函数来使用该作业。

function job_queue(){
    this.job = null;
    this.pointer = this.job;
    this.job_dispatcher = null; 
    this.length = 0;
}
job_queue.prototype.add_job = function( job ){
    if( this.job == null ){
        console.log('1st');
        this.job = {
            job:job,
            next:null
        };
        this.pointer = this.job;
        this.length = 1;
    }else{
        console.log('2nd');
        this.pointer.next = { 
            job:job,
            next:null
        };
        this.pointer = this.pointer.next;
        this.length++;
    }
};

job_queue.prototype.event_handler = function(){
        if( typeof this.job['job'] == 'undefined'){
            console.log('??');
        }
        if( this.job.job != null ){
            console.log('hi');
            this.job.job();
            this.job = this.job.next();
        }

}

job_queue.prototype.start_dispatch = function(){
    if( this.job_dispatcher == null ){
        console.log( this.event_handler );
        this.job_dispatcher = setInterval( this.event_handler,1000);
    }
}



var jq = new job_queue();
function a(){
    console.log('hi');
};
function b(){
    console.log('hi2');
}
jq.add_job(a);
jq.add_job(b);
jq.add_job(a);
jq.start_dispatch();

但是,当调用 event_handler 函数时,程序崩溃并显示日志

 if( typeof this.job['job'] == 'undefined'){

好像不能通过setInterval调用成员函数来访问成员变量。请问这几行代码到底是怎么回事,怎么才能达到目的呢?

setInterval() 不适用于 this。看这里:https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setInterval#The_this_problem

Code executed by setInterval() is run in a separate execution context to the function from which it was called. As a consequence, the this keyword for the called function will be set to the window (or global) object, it will not be the same as the this value for the function that called setTimeout.

您可以像这样在匿名函数中调用您的方法:

function job_queue(){
    this.job = null;
    this.pointer = this.job;
    this.job_dispatcher = null; 
    this.length = 0;
}
job_queue.prototype.add_job = function( job ){
    if( this.job == null ){
        console.log('1st');
        this.job = {
            job:job,
            next:null
        };
        this.pointer = this.job;
        this.length = 1;
    }else{
        console.log('2nd');
        this.pointer.next = { 
            job:job,
            next:null
        };
        this.pointer = this.pointer.next;
        this.length++;
    }
};

job_queue.prototype.event_handler = function(){
        
        if( typeof this.job['job'] == 'undefined'){
            console.log('??');
        }
        if( this.job.job != null ){
            console.log('hi');
            this.job.job();
            this.job = this.job.next();
        }

}

job_queue.prototype.start_dispatch = function(){
    var self = this;
    if( this.job_dispatcher == null ){
        console.log( this.event_handler );
        this.job_dispatcher = setInterval( function(){self.event_handler()},1000);
    }
}



var jq = new job_queue();
function a(){
    console.log('hi');
};
function b(){
    console.log('hi2');
}
jq.add_job(a);
jq.add_job(b);
jq.add_job(a);
jq.start_dispatch();

如果您在 event_handlerconsole.log(this),您会看到 this points to the Window object。这是因为它在 setInterval 中被调用。

job_queue.prototype.event_handler = function(){
        console.log(this); // <--- A Window object
        if( typeof this.job['job'] == 'undefined'){
            console.log('??');
        }
        if( this.job.job != null ){
            console.log('hi');
            this.job.job();
            this.job = this.job.next();
        }
}

一种解决方法是将 job_queue 引用存储为 self,然后按如下方式调用 setInterval

var self = this;
this.job_dispatcher = setInterval(function() {
     self.event_handler();
}, 1000);

代码片段:

function job_queue(){
    this.job = null;
    this.pointer = this.job;
    this.job_dispatcher = null; 
    this.length = 0;
}
job_queue.prototype.add_job = function( job ){
    if( this.job == null ){
        console.log('1st');
        this.job = {
            job:job,
            next:null
        };
        this.pointer = this.job;
        this.length = 1;
    }else{
        console.log('2nd');
        this.pointer.next = { 
            job:job,
            next:null
        };
        this.pointer = this.pointer.next;
        this.length++;
    }
};

job_queue.prototype.event_handler = function(){
        console.log(this);
        if( typeof this.job['job'] == 'undefined'){
            console.log('??');
        }
        if( this.job.job != null ){
            console.log('hi');
            this.job.job();
            this.job = this.job.next();
        }

}

job_queue.prototype.start_dispatch = function(){
    if( this.job_dispatcher == null ){
        console.log( this.event_handler );
        var self = this;
        this.job_dispatcher = setInterval(function() {
             self.event_handler(self);
        },1000);
    }
}



var jq = new job_queue();
function a(){
    console.log('hi');
};
function b(){
    console.log('hi2');
}
jq.add_job(a);
jq.add_job(b);
jq.add_job(a);
jq.start_dispatch();

正如其他人指出的那样,setInterval() 在不同的上下文中调用您的函数。这意味着传递给 setInterval() 的函数中 this 的值(在本例中为 event_handler())将不会指向正确的对象。

这个问题的一个很好的解决方案是 JavaScript 的 bind function:

this.job_dispatcher = setInterval(this.event_handler.bind(this), 1000);