1

I have defined my class like so:

function Slot(slot, maxSpeed, timer) {
this.slot = slot;
this.speed = 0;
this.maxSpeed = maxSpeed;
this.timer = timer;
this.interval = null;

this.go = function() {
    var $slot = $(this.slot);
    console.log(this.slot);
    $slot.addClass('motion');
    $slot.spStart();

    this.interval = window.setInterval(function() {
        var step = Math.floor(Math.random() * ((this.speed / 100) * 25)) + 1;
        if (this.speed < (this.maxSpeed / 2)) {
            this.speed += step;
        }

        if (this.speed >= (this.maxSpeed / 2)) {
            this.speed -= step;
        }
        console.log(this.slot);
        $slot.spSpeed(this.speed);
    }, timer);
};

$(this.slot).pan({ fps: '30', dir: 'down' });
$(this.slot).spStop();
}

The first console.log returns the expected value, but once I get into the setInterval function all variables (this.slot, this.speed) are all undefined? Even though I am still within their scope...

5 Answers 5

2

Scoping is a bit weird to get used to in Javascript, even weirder when you start using setInterval and setTimeout.

In your case, the this that's inside the interval is referring to the anonymous function itself. You can either assign 'this' to another variable outside the anonymous function:

var self = this;
this.interval = window.setInterval(function(){ /* use self here instead of this*/}

or you can call a function on the object in the interval step:

this.interval = window.setInterval(this.callback, timer);
Sign up to request clarification or add additional context in comments.

Comments

1

Your statement "Even though I am still within their scope" is incorrect. The 'this' variable is always set the functional context in which a function is executed, not in which it is defined. In this case, the function inside of setInterval is being executed from the window scope, and 'this' is actually window.

To get around this problem, I recommend using a closure: (notice the addition of the 'self' variable, and replacing nested 'this' calls with 'self'

function Slot(slot, maxSpeed, timer) {
    var self = this;
    this.slot = slot;
    this.speed = 0;
    this.maxSpeed = maxSpeed;
    this.timer = timer;
    this.interval = null;

    this.go = function() {
        var $slot = $(self.slot);
        console.log(self.slot);
        $slot.addClass('motion');
        $slot.spStart();

        self.interval = window.setInterval(function() {
            var step = Math.floor(Math.random() * ((self.speed / 100) * 25)) + 1;
            if (self.speed < (self.maxSpeed / 2)) {
                self.speed += step;
            }

            if (self.speed >= self.maxSpeed / 2)) {
                self.speed -= step;
            }
            console.log(self.slot);
            $slot.spSpeed(self.speed);
        }, timer);
    };

    $(self.slot).pan({ fps: '30', dir: 'down' });
    $(self.slot).spStop();
}

Comments

1

No, because this refers to something else inside setInterval. You'd need to define a static copy before like:

this.go = function() {
    var $slot = $(this.slot);
    console.log(this.slot);
    $slot.addClass('motion');
    $slot.spStart();

    var that = this;

    this.interval = window.setInterval(function() {
        var step = Math.floor(Math.random() * ((that.speed / 100) * 25)) + 1;
        if (that.speed < (that.maxSpeed / 2)) {
            that.speed += step;
        }

        if (that.speed >= (that.maxSpeed / 2)) {
            that.speed -= step;
        }
        console.log(that.slot);
        $slot.spSpeed(that.speed);
    }, timer);
};

Comments

1

this is simple, put

var self = this;

into this.go, and evrywhere in timer function replace this with self -

this.go = function() {
     var $slot = $(this.slot);
     console.log(this.slot);
     $slot.addClass('motion');
     $slot.spStart();
     var self = this;

     this.interval = window.setInterval(function() {
         var step = Math.floor(Math.random() * ((self.speed / 100) * 25)) + 1;
         if (self.speed < (self.maxSpeed / 2)) {
             self.speed += step;
         }

         if (self.speed >= (self.maxSpeed / 2)) {
             self.speed -= step;
         }
         console.log(self.slot);
         $slot.spSpeed(self.speed);
     }, timer);
 };

`

Comments

1

When setInterval() executes your callback method it does so outside your class context, so 'this' does not refer to your class. You must pass on your class's 'this' reference as an argument to your callback.

var that = this;
setInterval(function() {
  that.someVar ...
  that.someMethod() ...
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.