In 2001, Douglas Crockford evangelized private members design pattern and since then has been widely adopted by the Javascript community. However, are they really private?

Javascript is an extremely dynamic language in which it is possible to access a lot of things on way or another. We'll see how to get a reference to most of the "private" methods you can find in the wild.

Example

Here's a snippet of code from underscore.js. We are interested in getting a reference to the following "private" functions: lookupIterator and group.

(function() {
  /* ... */
 
  // An internal function to generate lookup iterators.
  var lookupIterator = function(value) {
    return _.isFunction(value) ? value : function(obj){ return obj[value]; };
  };
 
  // An internal function used for aggregate "group by" operations.
  var group = function(obj, value, context, behavior) {
    var result = {};
    var iterator = lookupIterator(value || _.identity);
    each(obj, function(value, index) {
      var key = iterator.call(context, value, index, obj);
      behavior(result, key, value);
    });
    return result;
  };
 
  // Groups the object's values by a criterion. Pass either a string attribute
  // to group by, or a function that returns the criterion.
  _.groupBy = function(obj, value, context) {
    return group(obj, value, context, function(result, key, value) {
      (_.has(result, key) ? result[key] : (result[key] = [])).push(value);
    });
  };
 
  /* ... */
}).call(this);

Here's the code to do it: (Demo on JSFiddle)

var lookupIterator;
var group;
 
_.isFunction = function() {
  lookupIterator = arguments.callee.caller;
  group = lookupIterator.caller;
};
_.groupBy();
 
console.log('lookupIterator', lookupIterator);
console.log('group', group);

The way it works is by hooking a function deep inside the internals of the module you want to break into and use arguments.callee.caller to get references to all the functions upward.

In this case, it was easy as we could hook _.isFunction. You can break into a lot of functions overriding String.prototype and using __defineGetter__.

Conclusion

Trying to break into existing Javascript code and make it do what you want is an extremely fun exercise. If this topic is of interest to you, take a look at this big list of Javascript attack vectors written by Google Caja team.

If you liked this article, you might be interested in my Twitter feed as well.
 
 

Related Posts

  • August 29, 2011 Javascript: Improve Cache Performance: Reduce Lookups (4)
    In my Binary Decision Diagram Library, the performance bottleneck was the uniqueness cache. By reducing the number of cache lookup, it is possible to greatly improve the performances. Common pattern In order to test if the key is already in the cache, the usual pattern is to use key […]
  • October 12, 2011 Intercept and alter <script> include (3)
    For a project, I want to transparently be able to intercept all the included javascript files, edit the AST and eval it. This way I can manipulate all the code of an application just by inserting a custom script. Hook the <script> tag insertion. Download the Javascript file […]
  • February 23, 2012 Dassault Systemes Javascript Evangelism Talk (5)
    I recently had the chance to do a 2-hour Javascript evangelism talk at Dassault Systèmes. Unfortunately the presentation has not been recorded. I reused my the presentation I did at EPITA at the beginning and added a second part with a lot of demos. I've written down notes about the […]
  • October 5, 2011 Javascript Presentation (2)
    The talk is over. Check out the Slides & Video. For several months now I've been surveying my friends and teachers at EPITA and I came to the conclusion that they have absolutly no idea what Javascript really is. In order to help them discover a language that is getting a lot of […]
  • September 24, 2011 Javascript: Cyclic Object Detection (17)
    URLON.stringify() suffer from a problem, when passed an object that contains a cycle, it will never stop. This article shows 3 techniques in order to detect if an object is cyclical. Edit the object: Mark In order to detect a cycle in an object, the method we learn at school is to […]