#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()
метод тоже подойдет.