Reputation: 7612
Consider the following contrived bit of JavaScript based on the revealing module pattern:
var RevealingModuleSample = function () {
var moduleName = "DefaultModuleName",
init = function (name) {
moduleName = name
},
issueAlert = function () {
alert(moduleName + " module is running");
}
return {
init: init,
issueAlert: issueAlert
};
} ();
RevealingModuleSample.init("SampleModule");
RevealingModuleSample.issueAlert();
Is there a way to transform the moduleName into a property with getter and setter methods and have those getter/setter methods called by internal references to moduleName? To give a concrete example, consider the following similarly contrived C# example:
public class ContrivedCsharpExample
{
private string _moduleName;
protected string moduleName
{
get {
// Perhaps some logging code here that records the moduleName was retrieved.
return this._moduleName;
}
set {
// Some code here that ensure that a valid moduleName was passed.
this._moduleName = value;
}
}
public void init(string moduleName) {
this.moduleName = moduleName;
}
public void issueAlert() {
Console.WriteLine(this.moduleName);
}
public static void Main()
{
var module = new ContrivedCsharpExample();
module.init("SampleC#Module");
module.issueAlert();
}
}
Notice that internally to the class, the methods are calling properties that have a getter/setter. This allows us to add additional code inside those getter/setter methods, whereas if we only used the properties available outside the class, the "init" and "issueAlert" methods would have to directly inspect the field, and any logic we had added to the getter/setter would be bypassed.
The problem I'm seeing is that in the revealing module pattern, the "moduleName" variable isn't a property on an object--it's just a variable that's currently in scope. So you can't just yank it out and replace it with a get/set pair. Right?
There is a related question on StackOverflow, but in that case the questioner is looking for a way to return an object with a property with getter/setter code, so that outside users of the module have their property access routed through the get/set methods. A solution is listed right in the question, but the solution provided doesn't allow code that is inside the module to access that property without directly operating on the variable, bypassing the get/set functions.
I'm thinking that this simply isn't possible with the revealing module pattern, is that correct? Is there a way to have calls inside the module routed through the get/set functions?
Upvotes: 2
Views: 1195
Reputation: 3248
There is a way to use IIFE's to get close to what you want, though I think it's overkill. However, you'll have to make a compromise -- instead of using properties you always have to use functions:
var Example = function () {
var moduleName = (function(moduleName){
return function(value){
if (val === undefined) return moduleName;
moduleName= val;
};
})("DefaultModuleName");
init = function (name) {
moduleName(name);
},
issueAlert = function () {
alert(moduleName() + " module is running");
}
return {
init: init,
issueAlert: issueAlert
};
} ();
Example.init("SampleModule");
Example.issueAlert();
The trick is to use an IIFE to return an accessor function. The function is a getter if invoked with no arguments, and it's a setter if invoked with an argument. The accessor function changes the value of the hidden variable in the IIFE's closure, and there is no way for anything outside the IIFE to access it except through the accesor function.
The revealing module pattern is a red herring in this case -- it doesn't have anything really to do with the question, and it's an anti-pattern as it's the worst of the implementations of the module pattern.
Upvotes: 0
Reputation: 25141
You are correct, in that you cannot define a setter/getter
on a variable. It must be a property of an object. The solution then is to convert the insides of your module into an object, while still exposing the same public API:
var RevealingModuleSample = function () {
var self = {
_moduleName: "DefaultModuleName",
set moduleName(name) {
console.log("setting module name: " + name);
self._moduleName = name;
},
get moduleName() {
return self._moduleName;
},
init: function (name) {
self.moduleName = name;
},
issueAlert: function () {
alert(self.moduleName + " module is running");
}
};
return {
init: self.init,
issueAlert: self.issueAlert
};
}();
RevealingModuleSample.init("SampleModule");
RevealingModuleSample.issueAlert();
The one consequence of exposing methods of an object, is the context or value of this
is lost when the methods are called. Hence the the use of self
inside the object, which is a simply reference to this
.
I suppose an alternative approach would be to store all the private variables in a separate object, but that seems less elegant to me.
Upvotes: 3