Должен ли я действительно иметь все эти «this.» внутри моего класса для всех переменных?

#javascript #class #oop #this

#javascript #класс #ооп #это

Вопрос:

Я практикую ООП в JavaScript, поэтому я написал этот пользовательский класс секундомера, который, похоже, работает правильно. Я могу создавать новые секундомеры (например, пусть sw = new Stopwatch();) затем оба sw.start() и sw.stop() это. При проверке времени, прошедшего как до, так и после его вызова с использованием sw.duration() .

(1) Однако в итоге я добавил this. -перед каждой переменной, что довольно уродливо и кажется излишним, но я не мог заставить его работать иначе. Итак, мне интересно, делаю ли я все это неправильно — или это лучший способ?

(2) У меня также нет constructor() . Должен ли я иметь один?

(3) Было бы целесообразно каким-то образом изменить мою duration() из функции в свойство или переименовать ее в getDuration ? Какова здесь наилучшая практика?

 class Stopwatch {
  start() {
    if (this.isRunning) throw new Error("Already running!");

    this.isRunning = true;
    this.startTime = new Date();
    console.log("Started...");
  }

  stop() {
    if (!this.isRunning) throw new Error("Not running!");

    this.isRunning = false;
    this.stopTime = new Date();
    console.log(`Stopped after ${this.duration()} seconds.`);
  }

  duration() {
    if (!this.startTime) throw new Error("Not yet started.");

    if (!this.isRunning) {
      // Stopwatch has been stopped
      this.timeDiff = (this.stopTime - this.startTime) / 1000;
    } else {
      // Stopwatch is still running
      this.timeDiff = (new Date() - this.startTime) / 1000;
    }

    return this.timeDiff;
  }
}

// Let's test a Stopwatch...
let sw = new Stopwatch();

// sw.start();
// sw.duration();
// sw.stop();
  

Обновление: Спасибо за все отличные ответы / комментарии! Для справки, вот мой обновленный код с реализованными предложениями.

 class Stopwatch {
  constructor() {
    this.isRunning = false;
    this.startTime = null;
    this.stopTime = null;
  }

  start() {
    if (this.isRunning) throw new Error("Already running!");

    this.isRunning = true;
    this.startTime = new Date();
    console.log("Started...");
  }

  stop() {
    if (!this.isRunning) throw new Error("Not running!");

    this.isRunning = false;
    this.stopTime = new Date();
    console.log(`Stopped after ${this.duration} seconds.`);
  }

  get duration() {
    if (!this.startTime) throw new Error("Not yet started.");

    let timeDiff = null;

    if (!this.isRunning) {
      // Stopwatch has been stopped
      timeDiff = (this.stopTime - this.startTime) / 1000;
    } else {
      // Stopwatch is still running
      timeDiff = (new Date() - this.startTime) / 1000;
    }

    return timeDiff;
  }
}

// Let's test a Stopwatch...
let sw = new Stopwatch();

// sw.start();
// sw.duration();
// sw.stop();
  

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

1. Если вы хотите, чтобы эти «переменные» были свойствами экземпляра объекта: да, вам нужно this для них. Вы также можете дополнительно использовать локальные переменные функции, если это имеет смысл, но они будут сохраняться только для этого одного вызова функции, как это делают локальные переменные функции. timeDiff вероятно, является кандидатом на такое использование.

2. Никогда не было проблем, this но можете ли вы распространить this оператор, чтобы он выглядел аккуратнее? Что-то вроде этого: const [timeDiff, isRunning, ....] = this;

3. Свойства экземпляра и переменные — это две совершенно разные вещи. Итак, вы должны указать их. Это не похоже, например, на Java или C #, где foo будет ссылка this.foo . Это связано с тем, что принципиально подход к OO в JS отличается, поэтому делать тот же вывод, что и Java / C #, будет очень запутанным и подверженным ошибкам — значение this определяется только во время вызова, и нет никаких проверок, чтобы убедиться, что foo оно включено даже this при его использовании. И если у вас есть переменная foo где-то в цепочке областей видимости, будет неоднозначно, какую из них выбрать.

4. «У меня также нет конструктора (). Должен ли я иметь один? » — да, вы должны инициализировать свойства вашего экземпляра в constructor ( this.isRunning = false; this.startTime = null; this.stopTime = null; ) .

5. » Было бы целесообразно как-то изменить мою duration() из функции в свойство » — вы можете использовать get duration() { … } , чтобы сделать его свойством getter, которое можно использовать как console.log(sw.duration) . Тем не менее, .getDuration() метод тоже подойдет.