this.method在setInterval中不起作用

ste*_*tep 3 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();
Run Code Online (Sandbox Code Playgroud)
<div id="timer"></div>
Run Code Online (Sandbox Code Playgroud)

出问题了,因为我遇到了2个错误:

this.viewer不是函数

此时间的NaN

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

将TIMER扩展为复位方法后:

reset: function() {
                    this.time = 100;
                }
Run Code Online (Sandbox Code Playgroud)

并在外部将其称为: Modules.TIMER().reset();

我有

这个时间没有定义

或在init内部:

jQuery("body").on('keyup mouseup', function (e) {
                        this.reset();
                    });
Run Code Online (Sandbox Code Playgroud)

我收到错误消息:

this.reset()不是函数。

Ter*_*rry 6

您的问题来自此行:

this.timer = window.setInterval(this.counter, 1000);
Run Code Online (Sandbox Code Playgroud)

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


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

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

this.timer = window.setInterval(this.counter.bind(this), 1000);
Run Code Online (Sandbox Code Playgroud)

this.timer = window.setInterval(this.counter, 1000);
Run Code Online (Sandbox Code Playgroud)
this.timer = window.setInterval(this.counter.bind(this), 1000);
Run Code Online (Sandbox Code Playgroud)


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

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

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

this.timer = window.setInterval(() => this.counter(), 1000);
Run Code Online (Sandbox Code Playgroud)

箭头函数保留lexical 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.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();
Run Code Online (Sandbox Code Playgroud)
<div id="timer"></div>
Run Code Online (Sandbox Code Playgroud)