#javascript #scope #settimeout
#javascript #область видимости #settimeout
Вопрос:
У меня есть класс, подобный:
function run(){
this.interval;
this.start = function(){
this.interval = setInterval('this.draw()',1000);
};
this.draw = function(){
//some code
};} var run = new run(); run.start();
однако, похоже, я не могу ссылаться / вызывать this.draw()
внутри setInterval, он говорит this.draw()
, что это не функция, и если я уберу кавычки, он скажет бесполезный вызов setInterval, что я делаю не так?
Ответ №1:
Метод bind()!
Смотрите следующий пример в ES6:
<!DOCTYPE html>
<html>
<body>
<canvas id="canvas" width="200" height="200" style="border: 1px solid black"></canvas>
<script>
class Circles {
constructor(canvas, r = 5, color = 'red') {
this.ctx = canvas.getContext('2d')
this.width = canvas.width
this.height = canvas.height
this.r = r
this.color = color
setInterval(
this.draw.bind(this),
1000
)
}
draw() {
this.ctx.fillStyle = this.color
this.ctx.beginPath()
this.ctx.arc(
Math.random() * this.width,
Math.random() * this.height,
this.r,
0,
2 * Math.PI
)
this.ctx.fill()
}
}
</script>
<script>
var canvas = document.querySelector('#canvas')
var circles = new Circles(canvas)
</script>
</body>
</html>
Комментарии:
1. @NickSteele Может быть, это связано с тем, что это вызывает дополнительный вызов функции перед каждым вызовом интервала
draw()
? Я согласен, что решение Yas более читабельно.2. Да!! Большое вам спасибо. Я так рад, что нашел этот ответ. Я пытался вызвать setInterval из конструктора класса JavaScript, но ни одна из моих переменных класса не была доступна. bind() решил это. 👍🏽
Ответ №2:
Значение this
устанавливается в зависимости от того, как вызывается функция. Когда вы вызываете функцию как конструктор, использование new
then this
будет ссылаться на создаваемый объект. Аналогично, когда вы вызываете функцию с точечной нотацией, как run.start()
тогда this
, будет ссылаться на run
. Но к тому времени, когда код, выполняемый вызывается setInterval
this
, не означает, что вы думаете. Что вы можете сделать, это сохранить ссылку на this
, а затем использовать эту ссылку, например, следующим образом:
function Run(){
var self = this;
self.start = function(){
self.interval = setInterval(function() { self.draw(); },1000);
};
self.draw = function(){
//some code
};
}
var run = new Run();
run.start();
Обратите внимание также, что вы создали вызываемую функцию run
и вызываемую переменную run
— вам нужно дать им разные имена. В моем коде (учитывая, что JS чувствителен к регистру) Я изменил имя функции, чтобы оно начиналось с заглавной буквы «R», что является соглашением для функций, предназначенных для запуска в качестве конструкторов.
РЕДАКТИРОВАТЬ: Хорошо, глядя на другие ответы, я вижу, что, возможно, я слишком усложнил это, и пока draw()
не нужно обращаться this
к нему, было бы хорошо просто сказать:
this.interval = setInterval(this.draw, 1000);
Но моя точка зрения о том, чтобы не присваивать вашему конструктору и более поздней переменной одно и то же имя, остается в силе, и я оставлю все self
это, потому что это техника, которая вам понадобится, если draw()
вам понадобится доступ this
. Вам также нужно было бы сделать это таким образом, если бы вы хотели добавить параметры в draw()
функцию.
Комментарии:
1.
this.draw
не будет работать, еслиdraw
нужно, чтобы правоthis
внутри него, когдаdraw
вызывается вsetInterval(this.draw, 1000)
версии,this
былоwindow
внутриdraw
. Всеself
это необходимо, еслиdraw
использует свойства экземпляра (т. Е. Если это действительно метод, а не просто простая функция).2. Верно. Когда я добавил свой «редактировать», я просто смотрел на
draw
содержащий «некоторый код», который может не понадобитьсяthis
, но тогда, вероятно, это будет не очень полезный метод, если это не так, так что… Я отредактирую свою правку…3. Спасибо за ваш ответ, удаление кавычек и () сработало, затем я заметил, что каждый раз, когда интервал запускает переменные внутри функции рисования, указывающие на это, не определено! затем я устанавливаю все в self, все решается, но я все еще не понимаю, почему и как это работает, не могли бы вы объяснить немного больше, пожалуйста? еще раз спасибо. 🙂 о, хорошо, это указывает на window внутри setInterval, КАК СТРАННО! в любом случае, есть ли лучший способ сделать это, self не выглядит правильным для меня :
4. Ну, вам не нужно вызывать переменную «self», но семантически так оно и есть. Некоторые люди вместо этого говорят «я» или что-то в этом роде. Многие люди вместо этого говорят «это», но я ненавижу «это», потому что оно неверно семантически («это» и «то» не должны быть одним и тем же). Как бы вы это ни называли, концепция по-прежнему остается лучшим способом сделать это (насколько я знаю). Для получения дополнительной информации о том, как работает «это», посмотрите, что MDN говорит об этом (или просто google «javascript this» и посмотрите, что получается).
Ответ №3:
function run(){
this.interval;
this.start = function(){
this.interval = setInterval(this.draw,1000);
};
this.draw = function(){
//some code
}
;}
var run = new run();
run.start();