1

All-

There is a classic pattern of implementing information hiding in Javascript as described by the great Douglas Crockford here:

http://javascript.crockford.com/private.html

I am also aware of another one I demonstrate here: http://jsfiddle.net/TvsW6/4/

And summarized as such:

function LogSystem(anotherPrivateVar) {
//. . 

  var _setting1;
  this.setting2;

  function _printLog(msg) {
    $("#" + _divId).append(msg + "<br/>");
  };

  return {
    printLog :function(msg) {
      console.log("PRINTING:" + msg);
      _printLog(msg);
    },
    logSetting_pub: function() {
       this.printLog("PUB: Setting1 is: " + _setting1);
       this.printLog("PUB: Setting2 is: " + this.setting2);
    }
//..
  };
};

QUESTIONS

Are there any other patterns beside these two that implement public and private methods and members in JavaScript? And are there names for these two patterns? And do you have a preference for the two (or more!)

Thank you so much for your help. I am finding that knowing advanced topics in raw JavaScript are rare skills and I'd like to have them!

Community
  • 1
  • 1
R Claven
  • 1,160
  • 2
  • 13
  • 27
  • I'm not a fan of your second method because the returned object itself doesn't end up with a type (it's not an instanceof `LogSystem`) and doesn't have a `LogSystem()` constructor function both of which are useful in some circumstances. – jfriend00 Feb 21 '14 at 08:12
  • I appreciate that argument. I am hoping there are trade offs but those are certainly disadvantages. Thank you! – R Claven Feb 21 '14 at 08:21
  • Hey so your comments really made me think. Would you please take a look here? http://stackoverflow.com/questions/21944115/advanced-javascript-the-alt-way-to-do-pub-priv-in-js-is-a-mystery – R Claven Feb 21 '14 at 20:03
  • OK, I read that post. What did you want to ask about it? – jfriend00 Feb 21 '14 at 22:23
  • Well if you have any incite into the questions there that would be great. The biggest mystery to me is how the "public" member but not the public method. Its like the functions have to be in the return object but the simple public variable does not. – R Claven Feb 21 '14 at 22:32
  • Do you understand the concept of a closure? The "private" variables live in a closure. They are NOT members of the main object. Also, do you understand what happens when you explicitly return an object from the constructor? That object becomes the result of the `new` operation rather than the type of object that the constructor would normally make. – jfriend00 Feb 21 '14 at 23:17
  • AH!! Yes I did know about how the retrun object then replaces what might have been the result of 'new.' I also do know abou closures but clearly not well enough bc that did not occur to me. Thank you for taking the time. – R Claven Feb 22 '14 at 23:04

3 Answers3

1

Crockford's method is probably the one I encounter the most. Frankly, it makes me pretty sad, because it is messy, semantically awful -- your constructor code is intermingled with your class definition! --, and if I recall my previous testing, inefficient.

I don't think I've ever seen the second style you describe in the wild. It also doesn't leave me very comfortable, for similar reasons to the first. Not to mention that returning from a constructor is a fairly obscure behaviour, that is likely to confuse many.

The style I favour is one of "contractual" privates, or perhaps more accurately, favouring "protected" members. A reasonably good example from myself can be found here.

A relevant subset of the code being:

var gk = (function(gk){

//static/constant members would be vars here, if I had them.

function List(collection){
    this._dummy = {};
    this._dummy.next = this._dummy;
    this._dummy.prev = this._dummy;
    this.length = 0;

    if(collection){
        this.addAll(collection);
    }
}

List.prototype = new gk.Collection();

//stuff...

List.prototype.pushBack = function(item){
    var curNode = this._dummy;
    var newNode = {};
    newNode.item = item;
    this._add(curNode, newNode);
}

List.prototype.add = List.prototype.pushBack;

List.prototype._add = function(curNode, newNode){
    newNode.prev = curNode.prev;
    curNode.prev.next = newNode;
    newNode.next = curNode;
    curNode.prev = newNode;
    ++this.length;
    this._registerAddition(curNode.item); //inherited from the superclass!
}

//stuff...

gk.List = List;

return gk;
})(gk || {}); 

All public and "private" members are attached to this or the prototype, but anything intended to be "implementation specific" is prefixed with an underscore. This indicates that it is not a publicly guaranteed API, and to refer to it would instantly tightly couple you with the implementation. This is great if you intend to have a publicly accessible object that can expose its internals to things that need them (such as my LinkedList, which is used internally by other data structures which may need more control, but is still a perfectly valid data structure on its own).

As an added benefit, the resulting code is (in my opinion) clean, maintainable, semantic, and members are uniformly accessed regardless of their "security". It is also much easier to refactor something to/from public/private status, as you just add/remove an underscore. You also get the full benefits of the prototype chain (abstract protected members for use by the super class!). As a consequence there seems to be a bit less overhead per instance (no tests on hand, sorry), if you care about that kind of thing.

I long ago gave up on trying to make JS into a perfect clone of Java/C++/C#. It's a different language. In my opinion, you might as well just make development easier on yourself, and make clean, readable, maintainable, and usable code, instead of creating frustrating monstrosities that ape other languages based on the glory of closures. Yes, you can do just about anything with a closure, but dear god that doesn't mean you should.

0

anotherPrivateVar is not a private member. It is a parameter of a function. In this case the parameter of your constructor. _setting1 cannot be declared otherwise.

I don't think your last two public functions printLog and logSetting_pub are the best way to define public functions. Use prototyping instead:

LogSystem.prototype.printLog = function(msg) {...}

Edit: You also might be interested in coffeescript. It has a better approach to develope object oriented with classes, constructors, etc. But mainly it's javascript in another syntax.

Felix
  • 2,531
  • 14
  • 25
  • `anotherPrivateVar` is a private variable. It happens to be an argument, but it is private and is a variable that can be read or set just like other variables. It is available to the `printLog()` method, but not available to the outside world (thus it's private). Further, the whole point of defining methods this way instead of using the prototype is exactly so that you can have private variables. I think you've missed the whole point of this technique. – jfriend00 Feb 21 '14 at 07:58
  • sure in javascript it is available in `printLog()` because `printLog()` is defined in the function itself. But that is only a Javascript behaviour, not an object oriented pattern. Besides that, a private variable is something other than a private member; I've overread that in the variableName (`anotherPrivateVar`), sorry. – Felix Feb 21 '14 at 08:51
0

My favorite pattern is described on Mozilla web-site:

Object.defineProperty(obj, "value", {
  enumerable: true,
  configurable: false,
  writable: true,
  value: 5
});

Also you could add getter and setter for such a property.

  • How does this create a private variable accessible only to a method? – jfriend00 Feb 21 '14 at 08:11
  • This is about creating members of a class. Have you read the url provided? – Iaroslav Karandashev Feb 21 '14 at 08:20
  • Yes, I've read that article and used it's techniques in actual projects. The unique and relevant part of that article (to the OP's question) is creating private variables that are accessible only by the methods which your answer does not do. – jfriend00 Feb 21 '14 at 08:25
  • WOW. Although you may not be answering my question precisely, this is absolutely related!!! If you have any examples of when this is an advantages way to give a property different attributes so as to be public, private or what have you, pls let us know. I am so surprised I didnt know this! – R Claven Feb 21 '14 at 08:51
  • @RClaven - you can't make things public/private with `Object.defineProperty()`. Properties of an object are visible to all. Private data is typically implemented not by adding properties to the object itself, but by hiding variables inside a closure that is only in scope for methods whose code resides inside the constructor. You can make properties read-only with `Object.defineProperty()`, but then they are read-only for everyone. – jfriend00 Feb 21 '14 at 22:26