SHARE
Facebook X Pinterest WhatsApp

Accessing Private Functions in JavaScript

Written By
thumbnail
Rob Gravelle
Rob Gravelle
Nov 12, 2012

JavaScript’s support for nested functions allows developers to place a function within another so that it is only accessible by its parent. This makes nesting helper function the ideal way to keep a function tightly coupled with the method which it supports. The downside to this model is that it tends to result in many functions that cannot be tested directly. Java implements the Reflection API for this and other purposes, so why shouldn’t JavaScript? Being the flexible language that it is, there certainly are ways to expose private functions for testing. In today’s article, we’ll examine one of them.

The Function as an Object

In JavaScript, the function is a first-class object. That affords us numerous ways in which to use them that other languages simply cannot. For example we can pass functions as arguments to other functions and/or return them. Functions also play a highly specialized role in Object creation, because objects require a constructor function to create them – either explicitly or implicitly. Another salient feature of the JavaScript language is that it is interpreted at runtime. This is relevant because code can be written and evaluated at runtime.

The idea behind this technique is that we can alter the initial constructor function by injecting our own code to expose the inner functions. The fact that we can access the raw code of the function allows us to both match function signatures in the source and append our own code. Here’s how it works, step by step:

The Person Class

Here’s a typical class/object that represents a generic Person. It’s defined using a constructor function so that we can instantiate it into specific persons. Our goal will be to expose all of the private functions that utilize the function xxx() signature:

var Person = function() { 
    //defaults
    var _age  =  0,
        _name = 'John Doe';
    
    var socialSecurity = '444 555 666';
    var bloodType      = 'O negative'
    //this is a global variable
    hatSize            = 'medium';
    var noValue;
    
    var aTest = function() {
      var nestedVar = 'nestedVar';
      var nestedFunction = function() {
        return 'nestedFunction';
      };
      
      alert('aTest');
    },
      anotherTest = function() {
        alert('anotherTest');
    };
    
    function test1() {
      alert('test1');
      var obj = { 
        test3: 'test3',
      bla:   234
      };
      
      function nestedFc() {
        alert('I am nested!');
      }
    }
    
    function test2() {
      alert('test2');
    }
    
    function test3() {
      alert('test3');
     
      return { 
        test3: 'test3',
        bla:   234
      };
    }
    
    this.initialize = function(name, age) {
      _name = _name || name;
      _age  = _age  || age;
    };
    
    if (arguments.length) this.initialize();
    
    //public properties. no accessors required
    this.phoneNumber = '555-224-5555';
    this.address     = '22 Acacia ave. London, England';
    
    //getters and setters
    this.getName     = function()      { return _name; };
    this.setName     = function (name) { _name = name; };
    
    //private functions
    function aFunction( arg1 ) {
      alert('I am a private function (ha!)');
    }
    
    //public methods
    this.addBirthday = function()      { _age++; };
    this.toString    = function()      { return 'My name is "+_name+" and I am "_age+" years old.'; };
}; 

The Reflection Class

It’s a good idea to group all of this highly specialized functionality within its own namespace, so that it doesn’t pollute the global environment. I called it Reflection. The Reflection class implements a method called createExposedInstance() that accepts the object constructor function. Calling the function’s toString() method returns the entire function source, including the signature and the body. Inserting our own code is easy because the function is always terminated by the closing curly brace character (}). Hence, returning the length of the function minus one provides the end-point of the function body.

The next thing that the createExposedInstance() method does is to collect the function definitions using a Regular Expression. It tends to results in some false-positives as we’ll soon see, but it’s easy enough to deal with those:

var Reflection = {}; 

Reflection.createExposedInstance = function(objectConstructor)
{
  // get the functions as a string
  var objectAsString    = objectConstructor.toString();
  var aPrivateFunctions = objectAsString.match(/functions*?(w.*?)(/g);
  //...
}

After executing objectAsString.match(), the aPrivateFunctions array contains the following function definitions. You may recognize some of those false-positives that I alluded to earlier:

  
  [function test1(,
   function nestedFc(,
   function test2(,
   function test3(,
   function aFunction(]

Creating the Exposed Instance

Inside the createExposedInstance() function, we append our own code to the constructor function body, close it back up by re-appending the closing curly brace, and wrap the entire function in an inline function, preceded by the new keyword ( new (function() {})() ):

  var funcString = "new ("
                 + objectAsString.substring(0, objectAsString.length - 1)
                 + ";this._privates = {};"
                 + "this._initPrivates = function(pf) {"
                 + "  this._privates = {};"
                 + "  for (var i = 0, ii = pf.length; i < ii; i++)"
                 + "  {"
                 + "    var fn = pf[i].replace(/(function\s+)/, '').replace('(', '');"
                 + "    try { "
                 + "      this._privates[fn] = eval(fn);"
                 + "    } catch (e) {"
                 + "      if (e.name == 'ReferenceError') { continue; }"
                 + "      else { throw e; }"
                 + "    }"
                 + "  }"
                 + "}"
                 + "nn})()";

  var instance = eval(funcString);
  instance._initPrivates(aPrivateFunctions);
  //...

Understanding the Function Exposing Code

Our code adds a public attribute called _privates. It’s an object that will contain each private function as a property. The _initPrivates() function accepts the same function constructor string (objectAsString) that we just appended our code to, but now, being an inner method allows _initPrivates() to reference the private functions, assuming that they are within its scope and executable JavaScript code. False-positives such as functions within Regular Expressions, string variables, as well as nested functions may also be captured. To weed those out, a for loop iterates over the aPrivateFunctions array and appends each function to the _privates object using eval() to convert the JS code into a real Function object. A try/catch placed around the eval line traps any resulting error. If the function is not accessible by the _initPrivates() method, a ReferenceError will result. These can be safely ignored. Any other error type is rethrown.

Once the functions have all been stored in the _privates object, the _initPrivates() method is deleted and the exposed instance is returned:

	// delete the initiation functions
	delete instance._initPrivates;

	return instance;
}

Calling Private Functions

After creating an exposed instance using the createExposedInstance() method, we can call private functions by name via the _privates object:

//create an instance of a person
var rob = Reflection.createExposedInstance(Person);

//call the private "aFunction" function
rob._privates['aFunction']();  //alerts "I am a private function (ha!)"
//rob._privates.aFunction() also works

Here is the source code in its entirety:

var Reflection = {}; 

Reflection.createExposedInstance = function(objectConstructor)
{
  // get the functions as a string
  var objectAsString    = objectConstructor.toString();
  var aPrivateFunctions = objectAsString.match(/functions*?(w.*?)(/g);
  
  // To expose the private functions, we create
  // a new function that goes trough the functions string
  // we could have done all string parsing in this class and
  // only associate the functions directly with string
  // manipulation here and not inside the new class,
  // but then we would have to expose the functions as string
  // in the code, which could lead to problems in the eval since
  // string might have semicolons, line breaks etc.
  var funcString = "new ("
                 + objectAsString.substring(0, objectAsString.length - 1)
                 + ";"
                 + "this._privates = {};n"
                 + "this._initPrivates = function(pf) {"
                 + "  this._privates = {};"
                 + "  for (var i = 0, ii = pf.length; i < ii; i++)"
                 + "  {"
                 + "    var fn = pf[i].replace(/(function\s+)/, '').replace('(', '');"
                 + "    try { "
                 + "      this._privates[fn] = eval(fn);"
                 + "    } catch (e) {"
                 + "      if (e.name == 'ReferenceError') { continue; }"
                 + "      else { throw e; }"
                 + "    }"
                 + "  }"
                 + "}"
                 + "nn})()";

  var instance = eval(funcString);
  instance._initPrivates(aPrivateFunctions);

  // delete the initiation functions
  delete instance._initPrivates;

  return instance;
}

var Person = function() { 
    //defaults
    var _age  =  0,
        _name = 'John Doe';
    
    var socialSecurity = '444 555 666';
    var bloodType      = 'O negative'
    //this is a global variable
    hatSize            = 'medium';
    var noValue;
    
    var aTest = function() {
      var nestedVar = 'nestedVar';
      var nestedFunction = function() {
        return 'nestedFunction';
      };
      
      alert('aTest');
    },
      anotherTest = function() {
        alert('anotherTest');
    };
    
    function test1() {
      alert('test1');
      var obj = { 
        test3: 'test3',
      bla:   234
      };
      
      function nestedFc() {
        alert('I am nested!');
      }
    }
    
    function test2() {
      alert('test2');
    }
    
    function test3() {
      alert('test3');
     
      return { 
        test3: 'test3',
        bla:   234
      };
    }
    
    this.initialize = function(name, age) {
      _name = _name || name;
      _age  = _age  || age;
    };
    
    if (arguments.length) this.initialize();
    
    //public properties. no accessors required
    this.phoneNumber = '555-224-5555';
    this.address     = '22 Acacia ave. London, England';
    
    //getters and setters
    this.getName     = function()      { return _name; };
    this.setName     = function (name) { _name = name; };
    
    //private functions
    function aFunction( arg1 ) {
      alert('I am a private function (ha!)');
    }
    
    //public methods
    this.addBirthday = function()      { _age++; };
    this.toString    = function()      { return 'My name is "+_name+" and I am "_age+" years old.'; };
}; 

//create an instance of a person
var rob = Reflection.createExposedInstance(Person); //new Person('Rob', 29); //still 29! (I wish!)

//document.write
rob._privates['aFunction']();  //alerts "I am a private function (ha!)"

Conclusion

Once again, I would like to stress that this technique is meant for specialized applications such as unit testing. There are usually very good reasons that private functions are private. Just because there are ways to get at them does not in any way imply that one should circumvent object member safeguards by exposing and calling its internal functions. At the same time, there needs to be a way to access these functions to conduct thorough unit testing. Just remember to keep the two usages separate.

Recommended for you...

The Revolutionary ES6 Rest and Spread Operators
Rob Gravelle
Aug 23, 2022
Ahead of Time (AOT) Compilation in Angular
Tariq Siddiqui
Aug 16, 2022
Converting a JavaScript Object to a String
Rob Gravelle
Aug 14, 2022
Understanding Primitive Type Coercion in JavaScript
Rob Gravelle
Jul 28, 2022
HTML Goodies Logo

The original home of HTML tutorials. HTMLGoodies is a website dedicated to publishing tutorials that cover every aspect of being a web developer. We cover programming and web development tutorials on languages and technologies such as HTML, JavaScript, and CSS. In addition, our articles cover web frameworks like Angular and React.JS, as well as popular Content Management Systems (CMS) that include WordPress, Drupal, and Joomla. Website development platforms like Shopify, Squarespace, and Wix are also featured. Topics related to solid web design and Internet Marketing also find a home on HTMLGoodies, as we discuss UX/UI Design, Search Engine Optimization (SEO), and web dev best practices.

Property of TechnologyAdvice. © 2025 TechnologyAdvice. All Rights Reserved

Advertiser Disclosure: Some of the products that appear on this site are from companies from which TechnologyAdvice receives compensation. This compensation may impact how and where products appear on this site including, for example, the order in which they appear. TechnologyAdvice does not include all companies or all types of products available in the marketplace.