简体   繁体   中英

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

I'm trying to make a simple task queue with setInterval with a linked-list. I created a class with linkedlist and a setInterval function will keep calling a member function to consume the job.

 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(); 

However, when the event_handler function gets called , the program crashes with the log

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

It seems like it can not access the member variable by calling member function with setInterval. I would like to ask what exactly happened with these lines of code and how can I achieve the goal?

As others have pointed out, setInterval() calls your function in a different context. This means that the value of this within the function passed to setInterval() (in this case, event_handler() ) will not be pointing to the correct object.

A great solution to this problem is JavaScript's bind function :

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

setInterval() doesn't work with this . See here: 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.

You can call your method inside an anonymous function like this:

 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(); 

If you console.log(this) in the event_handler , you'll see that this points to the Window object . This is because it is being called in 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();
        }
}

One workaround for it would be to store the job_queue reference as self , and then call setInterval as follows:

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

Code snippet:

 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(); 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM