2015-09-03 63 views
3

我想用setInterval和链表进行简单的任务队列。 我用linkedlist创建了一个类,一个setInterval函数将继续调用一个成员函数来使用该作业。Javascript类成员函数通过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。我想问一下这些代码行到底发生了什么,我该如何实现目标?

+0

看到这个答案对于如何'this'工作的一个解释:http://stackoverflow.com/questions/13441307/how-does-the -this-keyword-in-javascript-act-within-an-object-literal/13441628#13441628 – slebetman

回答

1

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

代码是在单独的执行上下文 到从它被调用的函数运行。因此,被调用函数的这个关键字 将被设置为窗口(或全局) 对象,它将不会与调用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();

+0

谢谢。有没有更好的方法来编写一个没有setInterval的作业队列? – Jian

+0

而且在链接这。job_dispatcher = setInterval(function(){self.event_handler()},1000);为什么调用self.event_handler()而没有包装到闭包中不起作用? – Jian

+0

我不确定队列的最佳方法是什么。也许看看承诺。或者你可以简单地拥有一个数组,在其中推送作业,并在add_job中调用你的事件处理程序。无论如何,我不认为你需要setInterval。至于为什么调用self.event_handler只能在匿名函数中工作:问题不在于setInterval的参数中的'this',而是执行该函数时分配的'this'。它只是运行你提供的功能和分配窗口。 –

0

如果console.log(this)event_handler,你会看到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();

+0

谢谢。我是新来的JavaScript,并不知道如何正确使用一些功能。 – Jian

2

正如其他指出,setInterval()调用你的函数在dif不同的背景。这意味着传递给setInterval()(在本例中为event_handler())的函数内的this的值不会指向正确的对象。

一个伟大的解决这个问题是JavaScript的bind function

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