Robert Brooks
Robert Brooks

Reputation: 166

how to change object properties using objects methods

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

Answers (5)

Jackson Ray Hamilton
Jackson Ray Hamilton

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

darma
darma

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

Artyom Neustroev
Artyom Neustroev

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

A fiddle.

Upvotes: 0

Nir Alfasi
Nir Alfasi

Reputation: 53525

You have two errors:

  1. you can't refer to 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)
  2. you wrote Function using capital F - change to lower case!

Upvotes: 0

Jakub Kotrs
Jakub Kotrs

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

Related Questions