how do I setInterval to call a function within a class

16,677

Solution 1

The value of this is set depending on how a function is called. When you call a function as a constructor using new then this will refer to the object being created. Similarly when you call a function with dot notation like run.start() then this will refer to run. But by the time the code run by the setInterval is called this doesn't mean what you think. What you can do is save a reference to this and then use that reference, like the following:

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

Note also that you've created a function called run and a variable called run - you need to give them different names. In my code (bearing in mind that JS is case sensitive) I've changed the function name to start with a capital "R" - which is the convention for functions intended to be run as constructors.

EDIT: OK, looking at the other answers I can see that just maybe I overcomplicated it and as long as draw() doesn't need to access this it would've been fine to just say:

this.interval = setInterval(this.draw, 1000);

But my point about not giving your constructor and later variable the same name still stands, and I'll leave all the self stuff in because it is a technique that you will need if draw() does need to access this. You would also need to do it that way if you were to add parameters to the draw() function.

Solution 2

The bind() method!

See the following example in 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>
Share:
16,677
fenerlitk
Author by

fenerlitk

Java, PHP, and Javascript developer

Updated on July 26, 2022

Comments

  • fenerlitk
    fenerlitk almost 2 years

    I have a class like:

    function run(){
    this.interval;
    this.start = function(){
        this.interval = setInterval('this.draw()',1000);
    };
    this.draw = function(){
        //some code
    };} var run = new run(); run.start();
    

    however I can't seem to reference/call this.draw() within the setInterval, it says this.draw() is not a function, and if I remove the quotes it says useless setInterval call, what am I doing wrong?

  • mu is too short
    mu is too short over 12 years
    this.draw won't work if draw needs the right this inside it, when draw is called in the setInterval(this.draw, 1000) version, this will be window inside draw. All the self stuff is necessary if draw uses an instance properties (i.e. if it really is a method rather than just a plain function).
  • nnnnnn
    nnnnnn over 12 years
    True. When I added my "edit" I was just looking at draw containing "some code" which may not need this, but then it probably won't be a very useful method if it doesn't, so...I'll edit my edit...
  • fenerlitk
    fenerlitk over 12 years
    Thanks for your answer, removing the quotes and the () worked, then I noticed every time the interval run the variables inside the draw function ponting to this was undefined! then I set everything to self, everything is solved, but, I still don't understand why and how this works, do you mind explaining a bit more please? thanks again. :) oh okay, so this points to window inside the setInterval, HOW WEIRD! anyway is there a better way of doing this, self doesn't look right to me :\
  • nnnnnn
    nnnnnn over 12 years
    Well you don't have to call the variable "self", but semantically that's what it is. Some people say "me" or something instead. A lot of people say "that" instead, but I hate "that" because it is wrong semantically ("this" and "that" should not be the same thing). Whatever you name it though the concept is still the best way to do it (that I know of). For more info on how "this" works have a look at what MDN has to say about it (or just google "javascript this" and see what turns up).
  • fadedbee
    fadedbee almost 6 years
    @NickSteele Could it be because it causes an extra function invocation before each of the interval's call to draw()? I agree that Yas's solution is more readable.
  • raddevus
    raddevus about 2 years
    Yes!! Thank you so much. So glad I found this answer. I was trying to call setInterval from JavaScript class constructor but none of my class variables were available. bind() solved it. 👍🏽