как мне настроить interval для вызова функции внутри класса

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