this.method在setInterval中不起作用

时间:2019-06-19 06:43:28

标签: javascript setinterval

我有这个简单的代码:

var Modules = (function() {
    'use strict';

    return {
        
        TIMER: function (){
            var timer = null;
            
            return {
                time: 100,
                init: function() {
   
                    this.counter();
                    this.timer = window.setInterval(this.counter, 1000);
                },
                counter: function() {
                    this.time -= 1;

                    if (this.time <= 0) {
                        window.clearInterval(this.timer);
                        alert('Time expired');
                    }
                    console.log(this.time);
                    this.viewer();
                    
                },
                viewer: function() {
                    document.getElementById('timer').innerHTML = this.time;
                }
            }
        }
    };
}());

Modules.TIMER().init();
<div id="timer"></div>

出了点问题,因为我有2个错误:

  

this.viewer不是函数

  

此时间的NaN

我的设计模式在间隔内运行有什么问题?

将TIMER扩展为重置方法后:

reset: function() {
                    this.time = 100;
                }

并以下列方式在外部调用: Modules.TIMER().reset();吗?

我知道了

  

此时间未定义

或在init内部:

jQuery("body").on('keyup mouseup', function (e) {
                        this.reset();
                    });

我遇到错误:

  

this.reset()不是函数。

2 个答案:

答案 0 :(得分:6)

您的问题来自此行:

this.timer = window.setInterval(this.counter, 1000);

当您使用setInterval方法调用回调时,回调函数中的this不再引用您的TIMER对象,而是引用window


解决方案A:使用.bind(this)将词法this绑定到回调

您需要将当前上下文绑定到回调:

this.timer = window.setInterval(this.counter.bind(this), 1000);

var Modules = (function() {
    'use strict';

    return {
        
        TIMER: function (){
            var timer = null;
            
            return {
                time: 100,
                init: function() {
   
                    this.counter();
                    this.timer = window.setInterval(this.counter.bind(this), 1000);
                },
                counter: function() {
                    this.time -= 1;

                    if (this.time <= 0) {
                        window.clearInterval(this.timer);
                        alert('Time expired');
                    }
                    console.log(this.time);
                    this.viewer();
                    
                },
                viewer: function() {
                    document.getElementById('timer').innerHTML = this.time;
                }
            }
        }
    };
}());

Modules.TIMER().init();
<div id="timer"></div>


解决方案B:在setInterval回调中使用ES6箭头功能

注意:就我个人而言,我更喜欢此解决方案,因为它使用ES6,但是如果您仍支持旧版浏览器并且不想转换您的JS,则这可能不是最佳解决方案。

另一种替代方法是在setInterval的回调中使用箭头函数,而不是直接将this.counter函数分配为回调:

this.timer = window.setInterval(() => this.counter(), 1000);

箭头函数保留词法this,因此,在调用this.counter()时,它将使用相同的上下文,即内部this将引用您的TIMER对象

var Modules = (function() {
    'use strict';

    return {
        
        TIMER: function (){
            var timer = null;
            
            return {
                time: 100,
                init: function() {
   
                    this.counter();
                    this.timer = window.setInterval(() => this.counter(), 1000);
                },
                counter: function() {
                    this.time -= 1;

                    if (this.time <= 0) {
                        window.clearInterval(this.timer);
                        alert('Time expired');
                    }
                    console.log(this.time);
                    this.viewer();
                    
                },
                viewer: function() {
                    document.getElementById('timer').innerHTML = this.time;
                }
            }
        }
    };
}());

Modules.TIMER().init();
<div id="timer"></div>

答案 1 :(得分:-1)

我从外面找到了重置的答案。 我这样更改了TIMER:

TIMER: (function (){
    // all stuff
}())

然后调用类似于:Modules.TIMER.reset();,然后按预期方式运行。