Ilya Trianggela
Ilya Trianggela

Reputation: 307

A property become undefined

I im making a Clock class, and it will generate time every second.

class Clock {
  constructor(template) {
    this._template = template;
    this._timer = null;
  }

  render() {
    var date = new Date();

    var output = this._template
      .replace("h", date.getHours())
      .replace("m", date.getMinutes())
      .replace("s", date.getSeconds());

    console.log(output);
  }

  start() {
    this.render();
    this._timer = setInterval(this.render, 1000);
  }
}

var clock = new Clock("h:m:s");
clock.start();

At first, it is normal. The output same as what i expect. Then, there will be an error TypeError: Cannot read property 'replace' of undefined. It is weird. Why my template property become undefined?

Upvotes: 0

Views: 63

Answers (2)

AKX
AKX

Reputation: 169338

Since this.render isn't an arrow function, it will lose its this binding when used via setInterval.

Either

  • make it an arrow function (render = () => { ... }), or
  • bind it in the setInterval call:
        this._timer = setInterval(this.render.bind(this), 1000);
    

Upvotes: 3

Sebastian Kaczmarek
Sebastian Kaczmarek

Reputation: 8515

You are passing this.render to the setTimeout function and therefore the this context is changed. You need to .bind(this) and everything will work as expected.

class Clock {
  constructor(template) {
    this._template = template;
    this._time = null;
  }

  render() {
    var date = new Date();

    var output = this._template
      .replace("h", date.getHours())
      .replace("m", date.getMinutes())
      .replace("s", date.getSeconds());

    console.log(output);
  }

  start() {
    this.render();
    this._timer = setInterval(this.render.bind(this), 1000); // <-- here
  }
}

new Clock('h:m:s').start();

Upvotes: 3

Related Questions