Refer to the main JavaScript object from functions that are methods in a subobject

While working with a javascript object, I ended up with this code:

var mainModule = {
    opt : {
        opt1: 'my option1',
        opt2: 'my option2',
        opt3: 'my option3',
    },
    init: function(options){
        jQuery.extend(this.opt, options);
        this.mainMethod();
    },
    mainMethod: function() {
        //do Stuff
        var color = this.opt.opt1;
    },
    secondaryMethod1: function(){/*stuff*/},
    secondaryMethod2: function(){/*stuff*/},
    secondaryMethod3: function(){/*stuff*/},
    secondaryMethod4: function(){/*stuff*/},

    thirdlyMethod1: function(){/*stuff*/},
    thirdlyMethod2: function(){/*stuff*/},
    thirdlyMethod3: function(){/*stuff*/},
    thirdlyMethod4: function(){/*stuff*/},
};

      

With this code, I often check the opt object with this.opt

because it this

is mainModule. But all the code starts to get messy with all the different methods so I ended up with this new code with a new level of depth in the main object.

var mainModule = {
    opt : {
        opt1: 'my option1',
        opt2: 'my option2',
        opt3: 'my option3',
    },
    init: function(options){
        jQuery.extend(this.opt, options);
        this.mainMethod.init();
    },
    mainMethod: {
        init: function() {
        //do Stuff
        var color = mainModule.opt.opt1;
        },
        other: function(){},
        functions: function(){},
        here: function() {}
    },
    secondary: {
        method1: function(){/*stuff*/},
        method2: function(){/*stuff*/},
        method3: function(){/*stuff*/},
        method4: function(){/*stuff*/},
    }
    thirdly: {
        Method1: function(){/*stuff*/},
        Method2: function(){/*stuff*/},
        Method3: function(){/*stuff*/},
        Method4: function(){/*stuff*/},
    }   
};

      

But with this new one I cannot use this.opt

because it is this

no longer mainModule.

With this kind of object, is there a better way to get the opt object? Is this new level of depth necessary or should I use perhaps pseudo-space?

0


source to share


2 answers


You can always customize the main module in the IIFE and store the parameters as a local variable in that function. Which looks like this:

var mainModule = (function() {
    // Keep the options out of the object that returned.
    // Hides the options to stop things like mainModule.options.opt1 = 'EVIL';
    var opt = {};

    return { 
        init: function(options){
            jQuery.extend(opt, options);
            this.mainMethod.init();
        },
        mainMethod: {
            init: function() {
                console.log(opt);
            },
            other: function(){},
            functions: function(){},
            here: function() {}
        },
        secondary: {
            method1: function(){},
            method2: function(){},
            method3: function(){},
            method4: function(){},
        },
        thirdly: {
            Method1: function(){},
            Method2: function(){},
            Method3: function(){},
            Method4: function(){},
        }
    };
}());

      



Now all your functions can just reference opt

- you don't even need to this

.

0


source


If you just want to access those options, then storing them in a closure at the top level, as @RobH suggests, will work fine. However, if you want to this

function "correctly" in general in your subobjects, you essentially need to bind the functions in them to the top level this

. The brute force method for this is in your top level function init

:

for (fn in this.secondary) {
    this.secondary[fn] = this.secondary[fn].bind(this);
}

      

Or equivalent. You can write a method bindAll

:

bindAll: function(section) {
    for (fn in section) {
        section[fn] = section[fn].bind(this);
    }
    return section;
}

      

Then do

this.bindAll(this.secondary);
this.bindAll(this.thirdly);

      



in your subroutine init

.

None of this is perfect. Basically the JS engine is this

not friendly to the type of line spacing you are trying to do, as I sympathize with. In JS, this

it only exists in one place and only one place, which is inside a function that sits directly above the object, and is not available "in the wild" as long as you define the object as a literal.

The exception is the constructor. You can take advantage of this fact and do

function MainModule() {
    this.secondary = {
        method1: function(){}.bind(this),
        ...
    };
}
var mainModule = new MainModule();

      

However, with this approach, there is no way to fit secondary

in the prototype as you might prefer, and it will live in every instance.

If it was me, I could just drop the towel and go back to our original structure / title.

0


source







All Articles