Reputation: 166
Hi Im trying to get my head around javascript oop and am running into a problem,I'm building a constructor class, in the class I define the properties now i want to define some methods that alter those properties, but when I instanciate the object and invoke the method the the consol tells me that the properties are undefined. I imagine that this might have something to do with scope, I`ve been looking around google alot but all introductory articles are basically the same.
heres a simplifed version of the code. In my example code I want a shape to move around on the canvas. the object it self will have the method which controls its movement (just to right for now). when i instantiate the object i call its moveRight method which should alter its xy coordinates. then every second i rendor it to the screen in a separate function which calls for the objects xand y properties
//here i define object
function Mechanoid(){
//object properties
this.life=100;
this.x=500;
this.y=200;
this.anArray=new Array(0, 0); //can i create an array like this? i know it works when called from outside the object
//object methods
this.moveAround=function(){
var clock=setInterval(Function () {
this.x=this.x+1; //console log says undefined
this.y=this.y+1;
this.anArray[0]=this.x; //console says cannot read propety of null
this.anArray[1]=this.y;
},1000);
}
}
//then instanciate
var mech=new Mechanoid;
mech.moveAround(); // calls method to change object properties
//A request for the x any y coordinates of mech object will be called in a render function where it
//will be drawn to the canvas.
Can anyone tell me why the properties are not accessible from within the object method? and what i have to do to access them? thanks... there's probably a bracket missing in the syntax or something I wrote it on the fly i don't think theres a syntax error in the original code , and i dont think thats the problem.
Upvotes: 0
Views: 5830
Reputation: 9466
When you use window.setInterval
(setInterval
is shorthand for window.setInterval
), you need to maintain a reference to your object.
When your callback function is executed, this
doesn't refer to the object where the setInterval
call originated from. window.setInterval
invokes your callback function in a different context, namely the context of window
.
One solution is to use var self = this;
. While the value of this
changes according to context, self
is an arbitrary variable that maintains a reference to whatever object you assign to it.
this.moveAround = function () {
var self = this;
var clock = setInterval(function () {
self.x = self.x + 1;
self.y = self.y + 1;
self.anArray[0] = self.x;
self.anArray[1] = self.y;
}, 1000);
}
Also, you need to change the "F" in "Function" to a lowercase f (function
, not Function
).
EDIT:
You can also use Function.prototype.bind
in ES5 environments. It returns a function that executes with its this
set to an object (in this case, the object that invoked moveAround
).
this.moveAround = function () {
setInterval(function () {
this.x = this.x + 1;
this.y = this.y + 1;
this.anArray[0] = this.x;
this.anArray[1] = this.y;
}.bind(this));
}
JavaScript's this
has been anecdotally-referred-to-as "broken". window.setInterval
is a prime example of where confusion arises. Always be aware of the context in which "this-functions" execute.
Upvotes: 2
Reputation: 4747
You lost the context (this
) in the setInterval
function. Try :
this.moveAround=function(){
var that = this;
var clock=setInterval(function () {
that.x=that.x+1;
that.y=that.y+1;
that.anArray[0]=that.x;
that.anArray[1]=that.y;
},1000);
}
}
Upvotes: 0
Reputation: 8715
Inside setInterval
handler this
refers to window
. You either need to use closure:
this.moveAround=function(){
var self = this;
var clock=setInterval(function () {
self.x=self.x+1; //console log says undefined
self.y=self.y+1;
self.anArray[0]=self.x; //console says cannot read propety of null
self.anArray[1]=self.y;
}, 1000);
}
}
or bind
a context to function:
this.moveAround=function(){
var clock=setInterval(function () {
this.x=this.x+1; //console log says undefined
this.y=this.y+1;
this.anArray[0]=this.x; //console says cannot read propety of null
this.anArray[1]=this.y;
}.bind(this), 1000);
}
}
Upvotes: 0
Reputation: 53525
You have two errors:
this
when you're nested two levels below the object (the other solutions show you how to work around it using var that = this;
one level above)F
- change to lower case!Upvotes: 0
Reputation: 6229
This is all about scope
.
function Mechanoid() {
var self = this; // cache this
// bla bla
this.moveAround = function() {
var clock = setInterval(function () {
self.x = self.x + 1; // no longer undefined
self.y = self.y + 1;
// continue this way
}
}
}
Upvotes: 0