SteGriff

Blog

Next & Previous

Notes on JavaScript public/private

Imagine we want to write a simulation of a House class with some private fields for storing internal information, and some public getters, setters, and other methods, which can use the internal information in a safe way. I'm going to use this as an example to explore some deeply JavaScripty concepts. This will be our basic chassis, the defining function:

function House()
{
}

Adding a public variable

Crockford tells us that anything added to this will behave like a public instance variable.

function House()
{
    this.town = "Southport";
}

var house1 = new House();
var house2 = new House();

console.log("House1", house1.town);
console.log("House2", house2.town);

//Output:
//House1 Southport
//House2 Southport

Adding a private variable

To make a private variable, we use a regular var phrase inside the defining function:

function House()
{
    this.town = "Southport";
    var instructions = "Leave parcels under fake rock"
}

var house1 = new House();

//Public - succeeds
console.log("Town", house1.town);

//Private - returns undefined
console.log("Instructions", house1.instructions);

Adding a public function

Now, what we have been calling the "defining function" is truly known as the "prototype". It is the mold by which other objects will be created. So it's a lot like a class.

We can attach a public function to the prototype in two different ways; when we're creating it, or afterwards.

function House()
{
    this.doorIsOpen = false;
    var instructions = "Leave parcels under fake rock"

    this.openDoor = function()
    {
        this.doorIsOpen = true;
    }
}

var house1 = new House();

console.log("Door is open?", house1.doorIsOpen);
house1.openDoor();
console.log("Door is open?", house1.doorIsOpen);

//Output:
//Door is open? false
//Door is open? true

And the equivalent addition by prototype:

function House()
{
    this.doorIsOpen = false;
    var instructions = "Leave parcels under fake rock"
}

House.prototype.openDoor = function()
{
    this.doorIsOpen = true;
}

var house1 = new House();

console.log("Door is open?", house1.doorIsOpen);
house1.openDoor();
console.log("Door is open?", house1.doorIsOpen);

//Output:
//Door is open? false
//Door is open? true

Now the gotcha

If you're from a classical background, like me, you might presume to write a public accessor to a private property. You might presume to do so in the prototypal way I just described:

function House()
{
    this.doorIsOpen = false;
    var instructions = "Leave parcels under fake rock"
}

House.prototype.getInstructions = function()
{
    //Throws an error - doesn't have access to instructions
    return instructions;
}

var house1 = new House();

//It isn't gonna work
console.log("Instructions", house1.getInstructions());

However, if we write it the constructor, there's no problem, because getInstructions becomes a closure:

function House()
{
    this.doorIsOpen = false;
    var instructions = "Leave parcels under fake rock"

    this.getInstructions = function()
    {
        //This works; inner functions in js have access to all the variables in the outer function
        return instructions;
    }
}

var house1 = new House();

console.log("Instructions", house1.getInstructions());