2

Basically what I am trying to do is write a re-useable getter/setter to expose variables using the module pattern

// the getter/setter
function pub (variable) {
    return function (value) {
        return (arguments.length ? variable = value : variable);
    }
}

var module = (function () {

    var publicVariable = 0;

    function test () {
        return publicVariable;
    }

    return {
        publicVariable: pub(publicVariable),
        test: test
    }
})();

The desired result is the following:

module.publicVariable();      // 0
module.publicVariable(1);     // 1
module.publicVariable();      // 1
module.test();                // 1

But instead I get:

module.publicVariable();      // 0
module.publicVariable(1);     // 1
module.publicVariable();      // 1
module.test();                // 0

I assume this is because the following line passes the current value of publicVariable to pub, therefore the only closure created is the one inside pub and there is no link to the variable itself.

publicVariable: pub(publicVariable),    // same as "pub(0)"

I know there is no way to pass by reference in javascript. So how else can I accomplish what I am trying to do? I do not care whether props are called by function or property.

i.e. either of the following are fine

module.publicVariable = "new value";
module.publicVariable("new value");

I am just getting really tired of writing:

function prop1f (value) {  return (arguments.length ? prop1 = value : prop1); }
function prop2f (value) {  return (arguments.length ? prop2 = value : prop2); }
function prop3f (value) {  return (arguments.length ? prop3 = value : prop3); }

return {
    prop1: prop1f,
    prop2: prop2f,
    prop3: prop3f
}

as this gets unruly quick on large projects with lots of user accessible properties.

thedarklord47
  • 3,183
  • 3
  • 26
  • 55
  • If those setters/getters aren't doing anything special, you shouldn't use them at all. Just use a standard property! – Bergi Jul 19 '16 at 21:56
  • how are properties made public in the module pattern? – thedarklord47 Jul 19 '16 at 21:58
  • You could simply create the variable itself inside `pub`, so that your own code will use the getter/setter instead of the `var publicVariable` directly. – Bergi Jul 19 '16 at 21:58
  • Just use `var module = {publicVariable: 0, test () { return this.publicVariable; }};` – Bergi Jul 19 '16 at 21:59
  • was hoping to use the module pattern so I could have private methods and variables as well as the publics. I was also hoping to avoid writing `this` everywhere – thedarklord47 Jul 19 '16 at 22:03
  • You still can wrap the object in an IEFE, it just wasn't necessary for this example. You can avoid `this` with a [static variable](http://stackoverflow.com/a/10711164/1048572), but you cannot avoid property references if you want public properties without cumbersome accessors. – Bergi Jul 19 '16 at 22:08
  • Not sure whether [(Revealing) Module Pattern, public variables and return-statement](http://stackoverflow.com/q/30545445/1048572) answers your question, if yes I'll close as a duplicate – Bergi Jul 19 '16 at 22:09
  • Since this is js not java or c#, you should reconsider the pattern of private var w/public getter and setters. The simpler thing to do in js is to just use a public var. The other thing you ought to reconsider is your avoidance of "this". In my opinion, "this" is often preferable to the closure. The Revealing Module Pattern's abuse of closure is what makes it work poorly with respect to overriding and inheritance. – I-Lin Kuo Jul 20 '16 at 16:16

1 Answers1

5

The problem is that this code:

function pub (variable) {
    return function (value) {
        return (arguments.length ? variable = value : variable);
    }
}

can work perfectly as a getter, but as setter: if you change the parameter itself (variable), that won't affect the item that was fed into the parameter. But if you change the internals of the parameter, that will propagate back.

Instead you can use javascript getters/setters:

var module = (function () {

    var publicVariable = 0;

    function test () {
        return publicVariable;
    }

    return {
        set publicVariable (value) {
            publicVariable = value;
        },
        get publicVariable () {
            return publicVariable;
        },
        test: test
    }
})();

module.publicVariable = 'New value';
console.log(module.publicVariable);

Demo:

var module = (function () {

    var publicVariable = 0;

    function test () {
        return publicVariable;
    }

    return {
     set publicVariable (value) {
            publicVariable = value;
        },
        get publicVariable () {
         return publicVariable;
        },
        test: test
    }
})();

module.publicVariable = 'New Value';
console.log(module.publicVariable);
console.log(module.test());

Another generic alternative:

var module = (function () {

    var publicVariable = 0;

    function test () {
        return publicVariable;
    }

    return {
        //This function can access `publicVariable` !
        publicVariable: function(value) {
            return (arguments.length ? publicVariable = value : publicVariable);
        },
        test: test
    }

})();

module.publicVariable('new Value');
console.log(module.publicVariable());

Demo:

var module = (function () {

    var publicVariable = 0;
    
    function test () {
        return publicVariable;
    }

    return {
        //This function can access `publicVariable` !
     publicVariable: function(value) {
         return (arguments.length ? publicVariable = value : publicVariable);
        },
        test: test
    }
    
})();

module.publicVariable('new Value');
console.log(module.publicVariable());
Ismail RBOUH
  • 10,292
  • 2
  • 24
  • 36