1

I am trying to understand how I can touch/change/increment my privately scoped variable x in the following script. I'm using the Module pattern here, and thought I could reach into and set the private variables from a public return module declared property or method, but nothing I'm trying is working. Related: when do you declare a new instance of func vs. accessing func as a static delcared variable?

    var func = (function() {
      var x = 1;
      var squareX = function() {
        return x * x;
      };
      var addOne = function() {
        x++;
      }
      return {
        X: x,
        Xq: squareX,
        AddOne: addOne
      };
    });

    func().X = 9; // expecting privately scoped x = 9
    func().AddOne(); // expecting privately scoped x = 10
    document.write(func().Xq()); // expecting 100 actual = 1
kstubs
  • 808
  • 4
  • 18

3 Answers3

3

The point of the module pattern is to create a persistent, private scope which is invisible from the outside. Unfortunately, every time you call func, you're creating a new scope (with new return functions and their closures), so all of your operations are discarded afterwards.

Instead of calling func multiple times, just do it once to setup the "module" (you can even do this immediately, with an IIFE), and then perform operations on the result.

var func = function() {
  var x = 1; // this is the private variable

  var squareX = function() {
    return x * x;
  };
  var addOne = function() {
    x++;
  };

  return {
    // Note, you can't just do "X: x,"
    // since that will just create a copy;
    // you have to use properties
    get X() { return x; },
    set X(val) { x = val; },

    Xq: squareX,
    AddOne: addOne
  };
};

var funcModule = func();
funcModule.X = 9;
funcModule.AddOne();
document.write(funcModule.Xq());

Note that the reason you need an explicit getter and setter for the X module property is because you need to be able to modify the inner (hidden) variable x. Properties are available in all modern browsers, including IE9+. If you're working in IE8 or below, you'll need to define explicit getX and setX methods, and call them directly (you won't just be able to do funcModule.X = 5).

voithos
  • 68,482
  • 12
  • 101
  • 116
  • OK, didn't realize that get; set; were part of the javascript language (always impressed with the language as I learn more). In the other example Matt demonstrates that you can write a getter as a function too, so that's cool. – kstubs Nov 11 '14 at 19:17
2

You need a setter, and you need an IIFE:

var func = (function() {
  var x = 1;
  var squareX = function() {
    return x * x;
  };
  var addOne = function() {
    x++;
  }
  return {
    X: function(value) {
      if (value !== undefined) {
        x = value;
      }
      return x;    // we can use this as a getter too!
    },
    Xq: squareX,
    AddOne: addOne
  };
})(); // <-- this actually runs the function - this makes it an IIFE

document.write("X is " + func.X() + "</br>");

func.X(9); // expecting privately scoped x = 9

document.write("now X is " + func.X() + "</br>");

func.AddOne(); // expecting privately scoped x = 10

document.write("now X is " + func.X() + "</br>");

document.write(func.Xq()); // expecting 100 actual = 100
Matt Burland
  • 44,552
  • 18
  • 99
  • 171
0

You're using the Revealing Module Pattern to hide your private instance variable. When using that pattern, you must use a setter of some kind to change your private instance variable. Here is another StackOverflow post where someone else was having the same problem.

I don't recommend that you use the Revealing Module Pattern. In fact, I just gave a talk at NationJS 2014 titled "The Revealing Module is an Anti-Pattern".

Community
  • 1
  • 1
I-Lin Kuo
  • 3,220
  • 2
  • 18
  • 25