0

Hello this is my first attempt at trying to write a JavaScript application so I'm new to writing OOP code using it.

The following code runs without any errors in the console:

// Main file for the application
$(document).ready( function()
{
    var app = new application;
    setInterval( app.run, 50 );

});

function application()
{
   var canvas = Raphael(10,0,400,400);
   this.molecule = new molecule( new Vec2(50,50),new Vec2(1,0),canvas );
   this.molecule.update(10);

   this.run = function()
    {

    }
}

However, this piece of code does not work:

// Main file for the application
$(document).ready( function()
{
    var app = new application;
    setInterval( app.run, 50 );

});

function application()
{
   var canvas = Raphael(10,0,400,400);
   this.molecule = new molecule( new Vec2(50,50),new Vec2(1,0),canvas );

   this.run = function()
    {
        this.molecule.update(10);
    }
}

It gives the following error in the console:

Uncaught TypeError: Object function molecule( pos,vel,canvas )
    {
        this.radius = 5;
        this.color = "red";

        this.canvas = canvas;

        this.pos = pos;
        this.vel = vel;

        this.circle = canvas.circle( this.pos.x,this.pos.y,this.radius );

        this.circle.attr("fill", this.color );


    } has no method 'update' 

Here is the source file containing the molecule object.

    // This 'class' handles a molecule, including movement and drawing.

    function molecule( pos,vel,canvas )
    {
        this.radius = 5;
        this.color = "red";

        this.canvas = canvas;

        this.pos = pos;
        this.vel = vel;

        this.circle = canvas.circle( this.pos.x,this.pos.y,this.radius );

        this.circle.attr("fill", this.color );


    }

 // Updates the molecule
    molecule.prototype.update = function( deltaTime )
    {
        this.pos += this.vel * deltaTime;
        this.setPosition(this.pos);
    }

    // Accepts a Vec2
    molecule.prototype.setPosition = function( pos )
    {
        this.circle.translate( pos.x-this.pos.x, pos.y-this.pos.y );
    }    

I'm sorry for the large amount of code I've posted, but I'm stumped why the first piece of code works while the second won't. Could anybody shed some light on it for me? Thanks a lot.

1

2 Answers 2

1

A common mistake, and it requires a good understanding of JavaScript to see what's happening here. The problem is this line:

setInterval( app.run, 50 );

This causes app.run to be called when the interval runs out without a proper this context. To ensure that run gets called with app as its this context, you need something like:

setInterval( function() {
    app.run();
}, 50 );

or with the latest JavaScript (only in very modern browsers):

setInterval( app.run.bind(app), 50 );

The this context of a function in JavaScript is determined by how the function is called. Basically, it gets determined by what object it is called on. For example, in app.run(), the run method is called on app and it'll work as expected. However, in a slightly different scenario

var fn = app.run;
fn();

the function is called on no object and thus this will not be set, leading to unexpected results. This is exactly what's happening in your case. The solution is to make sure that you pass a function which can be called on any object, and make that function call run on the right object.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks a lot for this! I'm new to the way it works in JavaScript and just expected this to work like it does in other languages.
@KarlJacques: The sooner you relieve yourself of that expectation, the better. If all languages worked the same, then they wouldn't be different languages.
0

You've detached the run method from the app. Pass a function that keeps them together.

setTimeout(function() { app.run(); }, 50);

Now the value of this in .run() will be the app object.


Also, there's no need to make a new run method for every application() object. You can put run on the application.prototype.

function application() {
   var canvas = Raphael(10,0,400,400);
   this.molecule = new molecule( new Vec2(50,50),new Vec2(1,0),canvas );
   this.molecule.update(10);
}

application.prototype.run =  function() {
    this.molecule.update(10);
}

Although if you did keep run in the constructor, you could then have it close over a variable that references the object, and so you could safely detach it.

function application() {
   var canvas = Raphael(10,0,400,400);
   this.molecule = new molecule( new Vec2(50,50),new Vec2(1,0),canvas );
   this.molecule.update(10);

   var self = this;

   this.run = function() {
       self.molecule.update(10);
   }
}

setTimeout(app.run, 50)

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.