Object-Oriented JavaScript: Implementing the Revealing Prototype Pattern
Coming to JavaScript from a language like Ruby or Java, object-oriented programming feels different. There are some great resources out there to help you make the transition, but it can take some time (and experience) to get used to JavaScript’s prototype-based, rather than class-based, object model.
One of the things that I found particularly tricky was figuring out how to simultaneously create objects efficiently and incorporate information hiding.
These two things are not too difficult to achieve on their own:
– If you want to create objects efficiently, you can place shared functions in a prototype rather than a constructor. That way, the functions aren’t copied for every object; they’re stored in the same prototype that each object (instance) references.
– If you want to hide information on your objects, you can use the revealing module pattern. Creating an object returns a set of public properties that can access private variables and functions that are otherwise not accessible outside of the closure.
The problem is that these two options don’t play nicely together. Private information stored inside the closure you used to implement the revealing module pattern isn’t accessible to the prototype, and no information in the prototype is hidden. Is there a way to have your cake and eat it too?
Short answer: yes. Enter the revealing prototype pattern.
Once you’re familiar with the revealing module pattern, implementing the revealing prototype pattern isn’t a giant leap. Both use something similar to an immediately-invoked function expression to return objects with only those properties that you want exposed.
For example, say we’re building an AI player for a tic tac toe game. We know that we want the player to have a move signature and to be able to make a move. To make a move, it might need to implement a few other functions (a minimax algorithm, a function to score the current state of the board, etc.).
If you just used the revealing module pattern, it might look like this:
This option effectively hides information so that we’re only exposing three properties (get/set the move signature and make a move), but it doesn’t enable us to create new players efficiently. Any time we call AiPlayer()
, all of the methods will be copied for the new instance.
Using prototypes, we could rectify this problem:
Now we can create new objects efficiently. Calls to new AiPlayer(moveSignature)
don’t copy all of our functions, just a reference to the prototype where they’re stored. The problem is that we’ve lost our information hiding - the minimax
and scoreBoard
functions are exposed publicly.
Using the revealing module pattern, we can get information hiding and efficient object creation:
Using the revealing prototype pattern, our constructor creates objects efficiently and hides private information. New AiPlayer
objects only store their own moveSignature
and a reference to the prototype, and the prototype only exposes a makeMove()
function.