Introduction to the Issue

I'm currently working on a piece of code that was put together by someone else on my team. All of his logic was in the index.html file, so I'm trying to factor it out into a modular library. Part of the reason is that I now need to include an AJAX and UI library and I want to avoid collisions. I'm not a JavaScript programmer by any stretch of the imagination, so I have been working to understand the process of moving the code to separate files.

The Goal

The goal of my endeavor is to factor out the code my team member wrote into a separate JavaScript file. The code should be namespaced so that after I import it I can call methods by namespace.method() instead of calling method() directly. This is to prevent collissions with other code. Furthermore, I need to be able to extend this namespace through other files. So including another file should allow me to call namespace.submodule.method().

Current References and Progress

The two articles I've been working with are Namespacing in JavaScript and JavaScript Module Pattern: In-Depth. To start with I just copied the entire script from the index.html page into its own file. I then re-arranged the code to be under an anonymous self-executing function with a single argument which is the instance. Every exposed variable or method is then placed under a generic variable module which is assigned as:

var module = instance || {};

The self-executing anonymous function is passed a variable already defined above it in the code to assign itself to.

The Specific Problem

The problem is that the singleton created by this code has public variables but no public methods. So, I can call namespace.variable without any problem, but if I try to call namespace.method(), I get an undefined error. I need help understanding exactly what syntax features of the language are making the variables public but not the methods.

I've made my current work available as a gist to facilitate viewing.

Recommended Answers

All 8 Replies

David, as far as I can tell the pattern should be good for both vars and methods but your code needs debugging.

There's an error at line 70, module.creature[i] = new Parousia.Unit();.

The error is Uncaught exception: TypeError: 'Parousia.Unit' is not a constructor.

Airshow

AirShow,

First, thank you so much for responding! I do know that such an error would occur in your environment. I just uploaded the second script minion.js to the gist which includes the class definition for the Unit class. As I understand this structure, there should be no issue as to what order those files are imported.

I personally still have this issue when attempting to call methods on the singleton from a JavaScript console:
TypeError: Object #<Object> has no method 'init'

Any thoughts?

what do you mean by

var module = instance || {};

is it deliberate?

As I'm understanding the paradigm, that line of code should return either the pointer to instance (which itself is an alias of Parousia, an empty object literal, in this context) or it should create a new object literal if instance has no reference. I'm following the recommendations set forth in the tutorial linked to above, but I don't understand how instance would never have a reference.

As I said, I'm nowhere near an expert JavaScript programmer, so I don't understand the language specifications that make this work.

David,

Here's the problem as I see it, and a suggested solution.

In parousia.js, var Parousia = {}; is immediately followed by a self-executing fn that attempts to put in place a bunch of public Parousia members (vars and methods).

When the self-executing fn tries to execute the line module.creature[i] = new Parousia.Unit();, Parousia.Unit(); does not exist, therefore an uncaught error is thrown and execution halts - check your error console. This will happen in my environment, your environment and all other environments. It cannot be otherwise because the method (actually a contructor) must exist before it is called and at the point where it is called it definitely does not exist.

Moreover, in the code you have published Parousia.Unit() is never defined, though Parousia.minion.Unit is defined in minion.js, which must be loaded after parousia.js otherwise Parousia will not exist and an error will be thrown. So the order in which these files are loaded does matter.

This apparantly circular problem can be resoved by:

  • moving all the statements that initialise Parousia.creature (ie lines 69 to 152) inside the init fn.
  • ensuring that Parousia.Unit() is defined or calling Parousia.minion.Unit() instead.
  • ensuring that Parousia.init() is called only when all other Parousia submodules/methods (or at least those needed by init()) are in place.

I can't guarantee that further fixes aren't necessary.

A point worth noting is that Parousia.minion is an independent singleton. It is only a submodule of Parousia insomuch as it is put in place with Parousia.minion = (function() {...}()). The same applies to any other submodule.

Airshow

Don't worry about var module = instance || {};. It's just defensive programming.

Don't worry about var module = instance || {};. It's just defensive programming.

I understand you concern,
but module EQ instance OR {}, is a perfect EMT ( error-masking-tool ), it defends your eyes from seeing some otherwise pretty obvious errors. Nothing beneficiary from that.

This line: "var Parousia = {};" is fundamental. So if for some unknown reason it went missing while having thee "defensive programming" line of code in place - there'll be no way to find out why is the whole app - "a sudden fail!?" - because you will be getting some completely unrelated error on some perfectly sound line of code which will confuse you even more or make you loose it completely.

Doing "var module = instance || {};" will not guard anything! In case of a missing global - You will be operating on a totally inaccessible local object instead of your targeted Parousia.

Now back to troubleshooting...

You have, from what I can see there, a property definition such as:

    Parousia.minion = (function() {
            var module = {};

            module.Unit = function() {
                this.id = 0;
                ...
                }
            }

            return module;
    }())

It should be:

    Parousia.minion = (function() {
            var module = {};

            module.Unit = function() {
                 this.id = 0;
                 ...
                 }
            return module;
    }());

And you have:

    var Parousia = {};
    (function (instance) {
        var module = instance || {};

        module.CANVASHEIGHT = 500;
        ...
        }
    }(Parousia));

It must be:

    var Parousia = {};
    (function (instance) {
        var module = instance || {};

        module.CANVASHEIGHT = 500;
        ...

    })(Parousia);

This is something that will get you started on beating other errors.
So make sure you have fun while doing that.

Cheers.

Airshow and Troy III,

Thank you both for your responses. Unfortunately, this endeavor was dropped in favor of dirty hacked code, so the changes were never realized in the codebase. There are obviously issues at a deeper level with the code being properly written in the first place. Still, I at least learned a lot from what you contributed. I'm marking the question solved.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.