Search code examples
javascriptmoduledesign-patternscross-reference

How to cross reference classes in Javascript


Is there a way to cross-reference an instance of a class or an instance variable from different namespaces, taking into account that it does matter in which order are the script files defined in the main html application. Actually I want to know if there is any possibility to cross reference two different class instances, one pointing to a reference defined in a different namespace, and another variable defined in the second class pointing back to the first one.

Suppose i have a main.js file where i define a class which uses some instance variables defined in another namespace, let's say in particle.js, where at the same time i define a variable pointing back to Main class public variable.

var Main = (function() {
    var p = new Particle();

    this.draw = true;
    this.width = 800;
    this.height = 600;

    function print() {
        console.log(p.width, ':', p.height);
    }

    return {
        draw : this.draw,
        width : this.width,
        height : this.height,
        print : print
    }
})();

function Particle() {

    this.width = Main.width;
    this.height = Main.height;
    this.print = function() {
        console.log(this.width, ':', this.height);
    }    
}


var p = new Particle();
p.print();
Main.print();

...and in the *.html the javascript files order would be:

<script src = 'main.js'></script>
<script src = 'particle.js'></script>

Actually this code is working as expected if you try it on firebug for example, but on the same logic on my real application, which is much complex, i got Main is undefined error in console. I know it's possible to simulate real class modules using AMD with Require.js for example, but i don't want to relay on AMD right now.


Solution

  • I did not manage to get your code work on Chrome or Firefox, i always get an error on Main.width.

    The matter is that you refer to Main inside particle when you Main has not been fully constructed yet.

    There is no straightforward solution, the best I can think is delaying part of the initialisation of your Main singleton after you defined the Particle class. Alternately you can also reorder your code to respect dependencies.

    You have to remember that in javascript your code is evaluated when you call it.

    Here are my two proposals:

    Solution 1: Delay Main initialisation partly

    // Main.js --> loaded first
    var Main = new (function () {
        this.draw = true;
        this.width = 800;
        this.height = 600;
    
        // delayed initialization method
        this.init = function ()
        {
            var p = new Particle();
            this.print = function () {
                console.log(p.width, ':', p.height);
            }
        }
    })();
    
    //Particle.js --> loaded second
    function Particle() {
        this.width = Main.width;
        this.height = Main.height;
        this.print = function() {
            console.log(this.width, ':', this.height);
        }    
    }
    
    // call the delayed init method
    Main.init()
    
    var p = new Particle();
    p.print();
    Main.print();
    

    Solution 2: Split in 3 files to respect dependencies

    //Particle.js --> loaded first
    function Particle() {
        this.width = Main.width;
        this.height = Main.height;
        this.print = function() {
            console.log(this.width, ':', this.height);
        }    
    }
    
    // Main.js --> loaded in second position
    var Main = (function() {
        var p = new Particle();
        this.draw = true;
        this.width = 800;
        this.height = 600;
        function print() {
            console.log(p.width, ':', p.height);
        }
        return {
            draw : this.draw,
            width : this.width,
            height : this.height,
            print : print
        }
    })();
    
    // Init.js --> loaded third
    var p = new Particle();
    p.print();
    Main.print();