Свойство становится неопределенным

#javascript

#javascript

Вопрос:

Я создаю класс часов, и он будет генерировать время каждую секунду.

 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();

  

Поначалу это нормально. Результат такой же, как я ожидаю. Затем появится ошибка
TypeError: Cannot read property 'replace' of undefined . Это странно. Почему мое template свойство становится неопределенным?

Комментарии:

1. Где вызывается конструктор часов? похоже, что template изначально уже не определено (или, вероятно, становится неопределенным до вызова render).

2. @briosheje извините, я должен его отредактировать.

Ответ №1:

Поскольку this.render это не функция со стрелкой, она потеряет свою this привязку при использовании через setInterval .

Либо

  • сделайте его функцией со стрелкой ( render = () => { ... } ), или
  • свяжите его в setInterval вызове:
         this._timer = setInterval(this.render.bind(this), 1000);
      

Ответ №2:

Вы переходите this.render к setTimeout функции и, следовательно, this контекст изменяется. Вам нужно .bind(this) и все будет работать так, как ожидалось.

 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();  

Комментарии:

1. Или используйте функцию со стрелкой 🙂

2. @NikitaMadeev да, это тоже возможно 😉