0

I am making a simple clock utilizing class methods. Here is the code:

class clock{
  constructor(date){
    this.hour = date.getHours();
    this.minute = date.getMinutes();
    this.second = date.getSeconds();
  }

    updateHours(){
      if (this.hour==24){
        this.hour= 0;
      } else this.hour++;
    }
    updateMinutes(){
      if (this.minute==60){
        this.minute= 0;
        this.updateHours();
      }
      else this.minute++;
    }

    updateSeconds(){
      if (this.second ==60){
        this.second = 0;
        this.updateMinutes();
    } else{this.second++;}
      return (console.log(`${this.hour}:${this.minute}:${this.second}`)); 
}
}

let date = new Date();
let myClock = new clock(date);

setInterval(myClock.updateSeconds(), 1000);


CASE #1:

The above outputs one line and never repeats. In the debugger, the program seems to just get stuck at the setInterval() line and never goes back into the supplied function. Why is this the case?

=====

CASE #2:

  • setInterval(myClock.updateSeconds, 1000)

When I do not include the parenthesis for the function, I should be getting the function description, correct? Why does this output undefined:undefined:NaN

=====

CASE #3:

  • setInterval("myClock.updateSeconds()", 1000)

When I put quotations around the function, everything starts working perfectly

=====

Please elaborate on the functionality of setInterval() and how these cases relate. I though I have the correct idea (in the sense that the function is simply evaluated and accepts a returned value as done so in Case 1). Anything helps! Thanks!

Albert Ngo
  • 37
  • 6
  • `setInterval(myClock.updateSeconds(), 1000);` should not have the `()` on the method – Taplar Apr 17 '20 at 20:03
  • Otherwise you may have to use `() => myClock.updateSeconds()`, if it is an issue with the `this` being lost. – Taplar Apr 17 '20 at 20:04

1 Answers1

0

You are not using setInterval correctly. You need to pass in a function or class method that will be executed at a later time. Currently, you are executing the method yourself, and you are passing a return value from that method to the setInterval

You also need to bind the method to the instance of your class, because when you pass a method to the setInterval it loses the this reference. this will point to the window object` not to the instance of your class.

Do it like this:

setInterval(myClock.updateSeconds.bind(myClock), 1000);

codesandbox example

Mdn Function.bind()

Ivan V.
  • 7,593
  • 2
  • 36
  • 53
  • So what you are saying is, I need to pass setInterval() a function TO run. Therefore I have to get rid of the parenthesis ```setInterval(myClock.updateSeconds,1000)``` However, since I have to ensure that I am calling a function, I can either utilize bind, or utilize an arrow function as mentioned above. Question: How come ```myClock.updateSeconds.bind(myClock)``` doesn't also immediately invoke the function (because it is technically being called with parenthesis) and allows for setInterval to work properly, as opposed to the original ```myClock.updateSeconds()``` – Albert Ngo Apr 18 '20 at 14:00
  • I looked into my question in the above comment. I realized that .bind() is not immediately invoking the function. If I were to, it would look include and extra () at the end of .bind(). ``` myClock.updateSeconds.bind(myClock)() ``` – Albert Ngo Apr 18 '20 at 14:51
  • return value of `bind()` is another function. From MDN docs - bind return value: "A copy of the given function with the specified `this` value, and initial arguments (if provided)." – Ivan V. Apr 18 '20 at 18:27
  • The point is that you need to **capture** the `this` context for the function that is passed to the `setInterval`. Put `console.log(this)` inside `updateSeconds` and try it without `bind` . With `bind` `this` will be `clock` and without it will be `Window` – Ivan V. Apr 18 '20 at 18:38