【问题标题】:Javascript class member function calling member function by setInterval, couldn't access member variableJavascript类成员函数通过setInterval调用成员函数,无法访问成员变量
【发布时间】:2015-09-03 22:35:30
【问题描述】:

我正在尝试使用带有链表的 setInterval 创建一个简单的任务队列。 我用linkedlist创建了一个类,一个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 调用成员函数来访问成员变量。我想问一下这些代码行到底发生了什么,我怎样才能实现目标?

【问题讨论】:

标签: javascript constructor setinterval member-functions


【解决方案1】:

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

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

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • 谢谢。有没有更好的方法来编写作业队列而无需 setInterval?
    • 还有链接 this.job_dispatcher = setInterval(function(){self.event_handler()},1000);为什么调用 self.event_handler() 而不包装成闭包不起作用?
    • 我不确定队列的最佳方法是什么。也许看看承诺。或者您可以简单地拥有一个数组,您可以在其中推送作业并在 add_job 中调用您的事件处理程序。无论如何,我认为您不需要 setInterval。至于为什么调用 self.event_handler 只在匿名函数中起作用:问题不在于 setInterval 的参数中的“this”,而在于执行函数时分配的“this”。它只运行您提供的功能并以此分配窗口。
    【解决方案3】:

    如果您在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);
    

    代码sn-p:

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

    【讨论】:

    • 谢谢。我是 javascript 新手,不知道如何正确使用某些功能。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-08
    • 2014-07-29
    • 1970-01-01
    • 2019-10-16
    • 2013-11-30
    相关资源
    最近更新 更多