-1

I am new to oop in js. I'm working on a HTML5 game using Box2dWeb and I decided that I should it make it completely oop based. So I created a physics class like this in a separate file called physics.js

(function(window) 
{
function Physics(element, scale){
//init world logic
    }

Physics.prototype.debug = function(){
           //debug draw logic
};

Physics.prototype.step = function(dt){
    //step logic
};

    //making this class(or object) visible on the global scope
    //so i can create vars of this type anywhere in the application
window.Physics = Physics;
}(window));

Now I have a main game.js file where I init all my game physics, graphics, assets, etc. Here are the contents:

(function(){
 function init(){
    var physics = new Physics(document.getElementById("b2dCanvas"), 30);
    console.log(physics);
    physics.debug();
}
window.addEventListener("load", init);
 }());

This file, initializes my Physics object without any problem. Ultimately this is what i want. Great! But, prior to this, the file was like this, without the init() function.

(function(){

    var physics = new Physics(document.getElementById("b2dCanvas"), 30);
    console.log(physics);
    physics.debug();
 }());

This apparently threw the error Uncaught TypeError: Cannot call method 'getContext' of null. This meant, the physics constructor was being called(and naturally element at this point was null) without me invoking it. How was that possible? My self-executing function in game.js should have initialized the Physics object right? What am I missing?

jaykumarark
  • 2,359
  • 6
  • 35
  • 53
  • As you already said, `element` was `null`. And in your `Physics` constructor you are trying to call a method on it, which is obviously not possible. – Bergi Mar 04 '13 at 20:05
  • @Bergi That's not what op asked – Madbreaks Mar 04 '13 at 20:08
  • @Bergi I already know that. I was more interested in the order of execution and the scope of the `Physics` class. Both `game.js` and `physics.js` were self executing functions. Perhaps, the order of declaring the scripts in the ` – jaykumarark Mar 04 '13 at 20:11
  • @jaykumarark it has nothing to do with the code in the other objects, it is because you are referencing an element before it is loaded. Plain and simple. Learn about the page lifecycle. DomReady, load, etc. – epascarello Mar 04 '13 at 20:15

4 Answers4

2

Your script was running before the HTML was fully parsed, and before your canvas element was added to the DOM. When you added window.addEventListener("load", init);, you made it run when the window.onload event was triggered. At that moment, the DOM was fully parsed.

In modern browsers, you could also replace that with

document.addEventListener("DOMContentLoaded", init);

That event will trigger when the DOM is ready, but doesn't wait for other resources like images (unlike onload).

Or, just add all your scripts just before closing the body tag. At that point, every HTML tag in the body will already have been inserted into the DOM.

bfavaretto
  • 71,580
  • 16
  • 111
  • 150
  • `load` event did the trick in my code. I was concerned about the order of execution, when I followed the latter snippet of `game.js` and the Physics class scope. But your tip makes sense: waiting for the dom to load completely :) Thanks :) – jaykumarark Mar 04 '13 at 20:13
  • @jaykumarark This should be what your looking for. Since that function in your last code example is self executing, Physics is instantiated. Since the target object isn't in the DOM yet, it returns null on your query. – Matt Lo Mar 04 '13 at 20:14
  • 1
    @jaykumarark The order of the execution is the order of the source code. The immediately invoked functions will be invoked *immediately* after their definition. If you have two of them in a row (or two ` – bfavaretto Mar 04 '13 at 20:16
1

This meant, the physics constructor was being called(and naturally element at this point was null) without me invoking it. How was that possible?

Becase you are calling it, using this syntax:

(function(){...}());
                ^^
               call

That will call the function when the script is parsed as part of the normal page script parsing, and will not wait for the document/DOM to be ready for you to manipulate. You'll want to either use some sort of document 'load' listener, or remove that particular syntax and call the function manually when you're sure the DOM is ready.

Madbreaks
  • 19,094
  • 7
  • 58
  • 72
0

The error has nothing to do with the Physics object not being ready. It has to do with the code inside of it trying to reference an element that is not on the page when the code is called.

It is simple you were calling

document.getElementById("b2dCanvas")

before the element was loaded on the page. When getElementById does not find anything it returns null.

So what your code looks like if you were to inspect it

var physics = new Physics(null, 30);

and element is null

function Physics(element, scale){  
    var ctx = element.getContext("2d");  //<-- where the error occurs since element is null

Hence the error: Uncaught TypeError: Cannot call method 'getContext' of null.

When you listen for the load event, that means the element is there so it loads with no problem. Other way of dealing with it is to add the script to the bottom of the page.

epascarello
  • 204,599
  • 20
  • 195
  • 236
  • Sounds like op knows that already, *"physics constructor was being called(and naturally element at this point was null) "* – Madbreaks Mar 04 '13 at 20:05
  • @Madbreaks the problem is the OP does not understand the page life cycle. – epascarello Mar 04 '13 at 20:17
  • I don't think that's true. I think op doesn't understand the function syntax he/she is using, based on the (literal) question asked. Oh well, op didn't accept *either* of our answers. :) – Madbreaks Mar 04 '13 at 20:44
0

My guess is that you're calling the function before the DOM is ready. Put the script include at the bottom of your code or even better just wrap all init a window load listener.

Tal
  • 1,298
  • 2
  • 10
  • 20