首页 > 解决方案 > this.method 不适用于 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();

我有

this.time 未定义

.

或在init内部:

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

我收到错误:

this.reset() 不是函数。

标签: javascriptsetinterval

解决方案


您的问题来自这一行:

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>


setInterval解决方案 B:在回调中使用 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>


推荐阅读