Using ECMAScript 5 get/set properties with revealing module pattern

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?

Answers


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();

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.


Need Your Help

How to use union in select clause?

sql postgresql select union

I have two tables (created here for example) like:

Rails: Multi-Select Image Picker

jquery ruby-on-rails ruby ruby-on-rails-3 forms

I am using Simple Forms and I have the following multi-select form working properly for both the new and edit views: