Reputation: 348
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...
Upvotes: 1
Views: 264
Reputation: 5572
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() ...
});
Upvotes: 1
Reputation: 11779
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);
};
`
Upvotes: 1
Reputation: 36339
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);
Upvotes: 2
Reputation: 154868
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);
};
Upvotes: 1
Reputation: 41832
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();
}
Upvotes: 1