Search code examples
javascriptconstructorsetintervalclearinterval

Property in object is undefined and clearInterval() not working


I have this piece of code:

class CombatLog {
constructor(){
    this.idMsg = 0;
    this.timerInterval;
}

startTimer(){
    this.timerInterval = setInterval(this.combatStartLog, 2000);
    $('#combatLog').empty();
}

combatStartLog(){
    console.log(this.idMsg);
    switch (this.idMsg){
        case 3:
            clearInterval(this.timerInterval);
            $('#combatLog').empty();
            break;
        case 2:
            $('<p>', {
                class: 'combatText',
                id: `${this.idMsg}`
            }).appendTo('#combatLog');
            $(`#${this.idMsg}`).append(`FIGHT!`);
            this.idMsg = 3;
            break;
        case 1:
            $('<p>', {
                class: 'combatText',
                id: `${this.idMsg}`
            }).appendTo('#combatLog');
            $(`#${this.idMsg}`).append(`Prepare your potions...`);
            this.idMsg = 2;
            break;
        case 0:
            $('<p>', {
                class: 'combatText',
                id: `${this.idMsg}`
            }).appendTo('#combatLog');
            $(`#${this.idMsg}`).append(`Unsheathe your weapons...`);
            this.idMsg = 1;
        break;
        default:
            this.idMsg = 0;
    }
}

The desired behavior would be:

  • I call the method startTimer()
  • It calls combatStartLog() as an interval
  • Each interval the property idMsg of the object falls into the corresponding case
  • case '3' clears the interval and breaks the loop.

What actually happens:

  • I don't know why in the first interval idMsg is instantiated as undefined even though its initial value is set in the constructor:

The constuctor

constructor(){
    this.idMsg = 0;
    this.timerInterval;
}
  • I 'fixed' the problem above adding a default case with the code this.idMsg = 0; and when it gets to case 3, idMsg is set to 0 but the interval is never cleared and the loop goes on and on and on forever.

Solution

  • By passing in the function to the setInterval function, when it is invoked, the 'this' variable loses context. So you need to make sure to bind 'this' of combatStartLog to the instance of CombatLog object:

    class CombatLog {
    constructor(){
    this.idMsg = 0;
    this.timerInterval;
    this.combatStartLog = this.combatStartLog.bind(this);}}
    

    When you call new CombatLog(), it calls the constructor function with 'this' as the new object being instantiated. By reassigning combatStartLog to combarStartLog bound to the new object, 'this' inside combatStartLog refers to the newly instantiated object.