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?
source to share
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
.
source to share
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.