JavaScript - владелец "этого"
Я следовал руководству по созданию секундомера JavaScript и пытаюсь расширить его для работы с несколькими секундомерами (несколькими экземплярами класса). Проблема, с которой я сталкиваюсь, заключается в том, что когда я пытаюсь отобразить текущее значение, когда часы тикают, мне нужно жестко закодировать экземпляр класса, потому что использование "this" не работает (в строке, где я использую console.log). Я сократил код до минимума, чтобы попытаться понять этот аспект, и вставил то, что у меня есть ниже:
function Timer(){
var time1 = null;
var time2 = null;
var timeLoop = null;
function getTime(){
var day = new Date();
return day.getTime();
}
this.start = function(){
time1 = getTime();
timeLoop = setInterval(function(){
time2 = getTime();
console.log(_Timer.duration());
//console.log(this.duration());
},500);
}
this.duration = function(){
return (time1 - time2) / 1000;
}
}
Я думаю, что ссылка ниже описывает мою проблему, но я не понимаю ее достаточно, чтобы применить ее здесь. Это связано с тем, что владельцем является this.start, а не только это, и как я могу изменить код, чтобы он работал с любым экземпляром Timer?
http://www.quirksmode.org/js/this.html
Я включил жестко закодированную строку значения и строку "это", которая не работает.
Спасибо,
Geraint
5 ответов
Если вы хотите иметь this
Чтобы быть согласованным, вы должны связать вызываемые функции.
Например,
setInterval(function() { /* code here */ }.bind(this), 500)
Таким образом, this
внутренней функции будет такой же, как и внешней функции.
Всякий раз, когда вы видите function
Вы можете принять значение this
меняется, поэтому внутри функции обратного вызова для интервала this
на самом деле window
, а не объект.
Простое решение - просто хранить this
в переменной
function Timer(){
var time1 = null;
var time2 = null;
var timeLoop = null;
function getTime(){
var day = new Date();
return day.getTime();
}
this.start = function(){
var self = this;
time1 = getTime();
timeLoop = setInterval(function(){
time2 = getTime();
console.log(self.duration());
},500);
}
this.duration = function(){
return (time1 - time2) / 1000;
}
}
this
не является локальной переменной, поэтому она не сохраняется в замыканиях. Вам нужно назначить локальную переменную:
this.start = function(){
var self = this;
time1 = getTime();
timeLoop = setInterval(function(){
time2 = getTime();
console.log(self.duration());
},500);
}
Пытаться:
function Timer(){
var time1 = null;
var time2 = null;
var timeLoop = null;
var _this = this;
function getTime(){
var day = new Date();
return day.getTime();
}
this.start = function(){
time1 = getTime();
timeLoop = setInterval(function(){
time2 = getTime();
console.log(_this.duration());
},500);
}
this.duration = function(){
return (time1 - time2) / 1000;
}
}
С помощью bind(this)
работает отлично.
var timer = {
start: function() {
setInterval(function() {console.log(this.duration());}.bind(this), 1000);
}
}
timer.start();
Но это может быть ненужным, если вы используете const
с функцией стрелки:
const timer = {
start() {
setInterval(() => {console.log(this.duration());}, 1000);
}
}
timer.start();
Обо всем по порядку. Javascript не поддерживает ООП на основе классов. Это ООП, а его наследование является прототипом.
Ниже приведен пример реализации прототипных функций ООП с вашим примером таймера:
function Timer(){
var time1 = null;
var time2 = null;
var timeLoop = null;
}
Timer.prototype.getTime = function(){
var day = new Date();
return day.getTime();
}
Timer.prototype.start = function(){
time1 = this.getTime();
timeLoop = this.setInterval(function(){
time2 = this.getTime();
console.log(this.duration());
}.bind(this),500);
}
Timer.prototype.duration = function(){
return (time1 - time2) / 1000;
}
Посмотрите на раздел "Пользовательские объекты" в JNscript Reintroduction MDN
Нет ничего плохого в том, как это показано в вашем уроке. Просто это более чистый способ и bind
звонок нужен только для console.log
заявление, которое в противном случае связывало бы this
как window
, Если вы избавитесь от этого, вы можете избавиться от bind
тоже.