tyrondis
tyrondis

Reputation: 3494

Privateness in JavaScript

I know you can achieve something as "privateness" in JavaScript by using closures and Immediate Invoked Functions.

But what if I need full featured prototyping? There simply is no way I know of of having private members in an object's prototype. If I used privileged methods I can have private variables and public methods but I lose the option of prototyping.

Douglas Crockford "forbids" the use of dangling (putting an underscore in front of an identifier to indicate that it is not part of the public interface).

But is it that bad to use it? Since there is no way to make it real private.

What is your opinion about this? How do you handle it?

Upvotes: 4

Views: 265

Answers (3)

Chris West
Chris West

Reputation: 905

Here is an example of how to allow prototypal functions to access private variables in all browsers:

var Book = (function() {
  var $ = {};

  var Book = function(newFirst, newLast) {
    // Private variables stored in an object literal.
    var _ = {
      author_first : newFirst,
      author_last : newLast
    };

    // Public privileged method for accessing private variables.
    this._ = function(key) {
      if(key === $)
        return _;
      throw new Error("The _() function must be called internally.");
    };
  };

  // Public accessor method.
  Book.prototype.getAuthor = function() {
    var _ = this._($);
    return _.author_first + " " + _.author_last;
  };

  return Book;
})();

var bookA = new Book("Chris", "West"),
    bookB = new Book("Douglas", "Crockford");
alert(bookA.getAuthor());
alert(bookB.getAuthor());

This is the same way that I implemented the Color class in jPaq.

Upvotes: 1

jAndy
jAndy

Reputation: 236022

Well at first, you don't really lose the prototyping-effect when using a functional-inheritance pattern. I just assume you're talking about The good parts, crockford also introduced a pretty easy and effective way to have shared variables for that pattern aswell. Which basically looks like:

var Human = (function(my, priv) {
    var my   = my || {},
        priv = priv || {};

    my.privatedata = "foobar";

    priv.walk = function() {
        console.log('walking');
        return priv;
    };
    priv.talk = function() {
        console.log('blah blah');
        return priv;
    };

    return priv;
}());

var Andy = (function(my, priv) {
    var my   = my || {},
        priv = Human(my, priv);

    priv.SpecialAndyThing = function() {
        console.log('bloggin at typeofnan.com');
        return priv;
    };

    return priv;
}());

var myAndy = Andy();
myAndy.talk().SpecialAndyThing();

You can even simply extend this techniqe to have somekind of super methods. Using cryptic variable-conventions like underscores or whatnot is just bad practice in general. Its confusing since nobody just knows what is going on there (probably that argument fails if you're the only one using the codebase).


However, ECMAscript Edition 5 introduces some goodys to have more "private" members in a prototype chain. One important method for that is .defineProperty, where you can define a property which does not "shallow" through. Would look like:

var Human = {};

Object.defineProperty(Human, 'privateStuff', {
    value:      'secret',
    enumerable: false
});

Now, the property privateStuff is not visible for an object that inherits from Human's prototype chain. Anyway, this stuff requires Javascript 1.8.5 and is only available in cutting edge browsers for now. See https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/defineProperty

Upvotes: 5

Manrico Corazzi
Manrico Corazzi

Reputation: 11371

You may be interested in JavaScript Design Patterns. It discusses the Module Pattern too.

Upvotes: 1

Related Questions