Monday, November 17th, 2008

Trying to be private in JavaScript

Category: JavaScript

Erik Arvidsson has an updated take on instance private, class private, package and friends.

One thing that shoots out at you is actually at the end:

Gmail was written without any true private members. We just use a naming convention.

We love to focus on little geek things like encapsulation, but once again… you can write amazing, complex applications without purity.

In his post, Erik talks about the various issues around getting privacy and how closure magic can be “very memory hungry since every instance needs its own function to encapsulate the local vars.”

He then walks through ideas on getting the best of both worlds (private but performant) and ends up with a version you can try that even allows you C++ “friends” semantics:

javascript

  1. var A;
  2. (function() {
  3.   var KEY = {};
  4.   A = ...;
  5.  
  6.   var friendKeys = {};
  7.   A.addFriend = function(id, key) {
  8.     friendKeys[id] = key;
  9.   };
  10.  
  11.   function getFriendPrivate(obj, id) {
  12.     return obj._getPrivateWithKey(friendKeys[id]);
  13.   }
  14.  
  15.   A.prototype.accessFriendPrivate = function(obj) {
  16.     return getFriendPrivate(obj).b;
  17.   };
  18. })();
  19.  
  20. var B;
  21. (function() {
  22.   var KEY = {};
  23.   B = ...;
  24.   A.addFriend('B', KEY);
  25. })();

Yet, after all that, he still doesn’t think you should use it :)

Posted by Dion Almaer at 9:44 am
9 Comments

++---
2.8 rating from 20 votes

9 Comments »

Comments feed TrackBack URI

By far the most pragmatic solution I’ve seen to the private members problem is in the as-yet-unreleased version 3.1 of Packer. This can rename any fields beginning with an underscore to some numeric name, e.g. ‘this._privateMethod()’ bcomes ‘this._5()’. This discourages others from trying to access these fields as their names may well change in later builds.

Comment by jcoglan — November 17, 2008

As with most things, choosing the right tool for the job is the name of the game.

If you have an object representing a VISA card account, it’s not unreasonable to have a private accountNumber field with a getter and setter, with the getter performing some sort of format verification (and the getter perhaps performing some sort of security validation to ensure the caller has rights to call it).

If you’re writing a game however, you may not want the cumulative overhead you’ll get if you have to call getEnemyPosition() every iteration of the main game loop instead of just calling enemy.position directly (I don’t know how much the overhead actually is, but it’s something, and it’ll add up).

Especially in JavaScript, where not only is it interpreted but you generally have choices in how you do things because of the dynamic nature of the language, as opposed to other languages that are more rigid and give you fewer options, it is pretty much always a good idea to stop and think about what you’re doing because the idioms and guidelines you’ve ported from other languages *might* not be the best choice in JavaScript (they frequently still are, and I think that’s a good place to start from, but not always).

Comment by fzammetti — November 17, 2008

I of course meant to say, when talking about the VISA account number, that the SETTER might have a format verification.

Comment by fzammetti — November 17, 2008

@jcoglan: qooxdoo do it nearly the same. In qooxdoo private fields begin with a double underscore though (protected with one underscore). Enforcing private fields with such a mechanism is a good thing. And it also makes code a lot less readable (obfuscation). For further information please have a look at this part of the documentation: http://qooxdoo.org/documentation/0.8/generator_config_ref#compile-dist.

Comment by wpbasti — November 17, 2008

Nothing like security through obscurity…..

Comment by TNO — November 17, 2008

Cons: Very memory hungry since every instance needs its own function to encapsulate the local vars.

I’m not doubting this but I’d like to see some actual numbers supporting this claim. I’m wondering at what point this memory consumption becomes a performance bottleneck. Does anybody know of any published research done in this area?

Comment by Menno — November 18, 2008

A closure doesn’t use a prototype chain for its enclosed variables hence it takes more memory due to multiple copies of the same value. The point at which is becomes a bottleneck if vary depending on the environment.

Comment by TNO — November 18, 2008

Correction: “bottleneck if vary” -> “bottleneck will vary”

Comment by TNO — November 18, 2008

I would like to share a way I found to achieve private instance state in JavaScript (with normal prototype methods). Check it out: http://www.codeproject.com/KB/ajax/SafeFactoryPattern.aspx

Comment by DuarteCunhaLeao — December 21, 2010

Leave a comment

You must be logged in to post a comment.