Access Specifiers in JavaScript

For quite some time now, I’ve wanted to write about how access specifiers actually work in JavaScript given that the language doesn’t natively support the construct of a class unlike most other languages such as Java, C++, Python, PHP etc where classes are pretty much the raison d’etre. Of course, another interesting aspect especially in JavaScript’s case is the myriad ways in which you end up abstracting a class which would make one believe that perhaps specifying encapsulation would also embody the same variety but turns out that isn’t the case. Encapsulation or access specifiers more generally are implemented in a very standard fashion in JavaScript. This post digs into that a little deeper.

FYI, access specifiers are constructs through which you control access to class properties. In JavaScript that would technically be function objects since there is no class as such. Also functions are first class objects meaning they can do everything that normal objects could do. Generally, there are three main access specifiers viz. public, private and protected. JavaScript does support inheritance but there is no real direct support for the protected specifier. Even if there’s a hack to get that in place, it’s not worth the effort since that would ruin the essence of JavaScript. Remember, it’s not your traditional OOP language. With that said, let’s define a very basic function class.

function Cube(x,y,z){

  //Private members  
  var _volume = 0;
  var _printVolume = function(){
      document.write('Cube Volume = '+_volume);
  }

  // Public members  
  this.x = x;
  this.y = y;
  this.z = z;

  this.calcVolume = function(){
      _volume = this.x * this.y * this.z;
      _printVolume();
  }
}

var myCube = new Cube(2,3,5);
myCube.calcVolume();

Since myCube is an instance of Cube, it’ll have access to all the public members of Cube. There are of course other ways to add public members to the class object. This is where the prototype keyword comes into play. Generally, when you use the prototype to add methods or properties to the object, you’re essentially making them accessible to everyone(public). So be sure what you end up exposing via the prototype. Now, I’ll modify the above class using an explicit constructor to initialize things as opposed to doing it all with the main object function itself. Makes for cleaner and better structured code. I’m also adding some private static members to the function. They’re declared outside but before the constructor.

var Cube = function() {
    // private static member
    var cube_color = 'red';

    // private static functions
    function changeColor(new_color) {
        cube_color = new_color;
    }

    function getColor() {
        return cube_color;
    }

    // Private members    
    var _volume = 0;
    var _printVolume = function() {
        document.write('Cube Volume = ' + _volume + '<br/>');
    }

    // Public constructor    
    function init(x, y, z) {

        this.x = x;
        this.y = y;
        this.z = z;

        // Privileged Method can access private variables and methods
        this.calcVolume = function() {
            _volume = this.x * this.y * this.z;
            _printVolume();
        };
    };

    // Add methods via the prototype
    init.prototype.calcSurfaceArea = function() {
        var totalSurfaceArea = 2 * this.x * this.y + 2 * this.y * this.z + 2 * this.x * this.z;
        document.write('Cube Surface Area = ' + totalSurfaceArea + '<br/>');
    }

    init.prototype.changeColor = changeColor;
    init.prototype.getColor = getColor;

    return init;
}();

var cube1 = new Cube(2, 3, 5);
var cube2 = new Cube(5, 5, 5);
cube1.calcVolume();
cube2.calcVolume();

cube1.calcSurfaceArea();
cube2.calcSurfaceArea();

// Add methods from the outside using the prototype
Cube.prototype.calcFrontSurfaceArea = function() {
    var frontSurfaceArea = 2 * this.x * this.y + 2 * this.y * this.z;
    document.write('Cube Front Surface Area = ' + frontSurfaceArea + '<br/>');
}

cube1.calcFrontSurfaceArea();

// Explore the static variables
document.write('Cube Color = ' + cube1.getColor() + '<br/>'); // puts 'red'

// Now affect the static variable. 
cube1.changeColor('blue');
// puts 'blue'. Notice we're calling it using cube2 and not cube1
document.write('Cube Color = ' + cube2.getColor() + '<br/>');

If I hadn’t added the private static methods changeColor and getColor to the prototype, we wouldn’t be able to access them since they are private members and not accessible to instances cube1 or cube2. Also note why I added them within the class. If I tried adding them outside the class, it would fail since they exist only within the scope of Cube.

Well that’s just the tip of the iceberg as far as one interesting JavaScript feature goes. I’m looking forward to write more about other features soon. It helps me solidify my concepts too. So stay tuned…