0

How do I fix createBar() so that a private property bar is created at the same level as the property foo?

var x = (function() {
  var foo = "a";

  function createBar() {
    this.bar = "b";
  }

  return {
    getFoo: function() {
        return foo;
    },
    getBar: function() {
        return bar;
    }
  }; // end: returned object
}());

This is how the module should work:

x.getFoo(); // returns a
x.getBar(); // returns b
window.bar; // is undefined (but in my example, it is b)

Update:

This is what I am doing now:

var x = (function() {
  var data = {};  //private object holding state variables
  data.foo = "a"; // one state variable

  function createBar() {
    data.bar = "b"; // another dynamically created state variable
  }

  return {
    getFoo: function() {
        return foo;
    },
    getBar: function() {
        return bar;
    }
  }; // end: returned object
}());

but somehow I don't like it. What would you do, to share state informations between private functions?

Pascal Rosin
  • 1,498
  • 16
  • 27
  • You should either consistently use getters/setters to enforce encapsulation or not (with JavaScript you have other options), but alternating approaches will introduce confusion. By *private* it sounds like you mean *public*? Basically anything that is returned from the module represents the public API. – Matt Whipple Oct 21 '12 at 12:58
  • @MattWhipple no I mean private. `createBar()` should be a private function and `bar` should be a private property like `foo`. Of course in my real example it is not supposed to only create a property but to do some stuff and store some data in private scope for other private functions to be invoked later by public functions. – Pascal Rosin Oct 21 '12 at 13:10
  • Ahh...I misread the commented code. – Matt Whipple Oct 21 '12 at 13:21

2 Answers2

1

window.bar; // is undefined (but in my example, it is b)

calling your private method createBar will end up in a new object with a property bar = 'b'

its private due it cant be read its properties from outside you could store a object reference to access it but i dont think its what you are looking for...

by defining another var it is in the scope of both functions:

var x = (function() {
    var foo = "a";
    var bar;

    function createBar() {
        bar = "b";
    }

    return {
        getFoo: function() {
            return foo;
        },
        getBar: function() {
            return bar;
        }
    }; // end: returned object
}());

dont forget to call createBar() otherwise bar will be undefined...

ChaosClown
  • 367
  • 2
  • 16
  • Hmm, no due to an error in Javascript, the `this` in my method `createBar()` links to the top level object window. So the method creates `window.bar` and that is not private. My problem with your Answer is that I cannot add properties dynamically this way. – Pascal Rosin Oct 21 '12 at 15:48
0

Removing the this and declaring bar within the outer function would be the lightest weight solution: however your solution of using the internal data object is the more flexible (though you should be updating your getters to do things like return data.foo;).

The primary advantage for using the data object would be that if you are building a library of JavaScript code you'd be able to call external functions/mixins within the constructor/private scope of the object you're creating, while still ending up with a defined interface. As a contrived example if you were doing something like creating an Adapter style of object, you'd be able to call something like linkWithWebService(data) which could populate and add behavior to your privately scoped members upon construction (and those calls would have direct access similar to nested classes in other languages), but all future behavior would still be limited by your defined API.

Or from personal experience I created an API where the accessors followed the pattern of getter: attributeName() and setter: attributeName(newValue) which I implemented by creating a higher order function to create the getter and an internal data object. Then in the constructor return I did something like attributeName = makeAccessor(attributeName, data) so the created function became the only exposure of the attribute.

Matt Whipple
  • 7,034
  • 1
  • 23
  • 34