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.