Friday, January 25, 2013

JavaScript: OO programming using the Revealing Prototype Pattern

I’m currently playing around with SPA (Single Page applications), meaning a lot of JavaScript to write. One of the principals in OO programming is don’t repeat your self. That is why I was looking for ways to accomplish this. In languages as C#, Java, VB, … we can make use of classes for this, but in JavaScript we don’t have a keyword class to define classes. (Except if you are using Typescript, this is a language build on top of JavaScript that allows you to define classes like you do in C# or Java. You should really check it out.)

Closures

In JavaScript you only have functions, but all these functions have closures. A closure is a special kind of object that combines two things: a function, and the environment in which that function was created. The environment consists of any local variables that were in-scope at the time that the closure was created. In the example below the “obj” variable is a closure which has “Hello world!” and the function innerFunction in scope when the closure was created.

   1: function closure(){
   2:     var hello = "Hello";
   3:     function innerFunction(suffix){
   4:         alert(hello + " " + suffix);
   5:     }
   6:     return innerFunction;
   7: }
   8:  
   9: var obj = closure(); // Creates a new closure
  10: obj("world!"); // This will show the message box with "Hello world!"

The innerFunction also has his own closure containing the suffix variable. Because the innerFunction is inside of an other scope, it can make use of the parent scope as long as it is created in the parent scope, and there aren’t duplicate names. In the case inner- and outer scope have the same variable or function defined, the value of the inner scope will be the one defined in the inner scope.



   1: function a(){
   2:     var c = "1"
   3:     function b(c){
   4:         alert(c);
   5:     }
   6:     return b;
   7: }
   8:  
   9: var x = a();
  10: x("5"); // The message box will show 5.

Objects


To create a new object in JavaScript, we need to do 2 things. First make a class definition using a function. In the example bellow we define the class in the function “Class”. You see we can have private fields and private methods inside. Because none of this 2 are returned at the end, they will only exist inside the closure and be only accessible inside it. At the end of the class definition we return an object literal. This object literal will contain all the public functions and fields the object has.



   1: function Class(){
   2:     var privateField = "private"
   3:     function privateFunction(){
   4:         return privateField;
   5:     }
   6:  
   7:     return {
   8:         publicField: "public",
   9:         publicFunction: function(){
  10:             return privateFunction();
  11:         }
  12:     }        
  13: }
  14:  
  15: var instance = new Class();
  16: alert(instance.publicField); // shows "public"
  17: alert(instance.publicFunction()); // shows "private"

There is also a second way to expose fields and functions public. You can do this by adding the fields and the functions to the scope of the function. You can access the scope of a function, by using the this keyword.



   1: function Class() {
   2:     var privateField = "private"
   3:     function privateFunction() {
   4:         return privateField;
   5:     }
   6:  
   7:     this.publicField = "public";
   8:     this.publicFunction = function () {
   9:         return privateFunction();
  10:     };
  11: }
  12:  
  13: var instance = new Class();
  14: alert(instance.publicField); // shows "public"
  15: alert(instance.publicFunction()); // shows "private"

Prototype Pattern


In the objects chapter of this post I showed you 2 ways to define a class. The disadvantage of the above code is that everything inside the class definition gets created when you create a new instance of the class. When creating a lot of instances you can imagine that you will get memory issues after a while. That is when the prototype pattern can come to the rescue.


The prototype pattern is a creational design pattern used in software development when the type of objects to create is determined by a prototypical instance, which is cloned to produce new objects (Source Wikipedia). This means instead of creating the entire object every time, only the state (which makes the object instances unique) will be created, but all the other stuff like methods will be cloned. By doing this you can save a lot of memory allocation.


In the example below you can see the prototype pattern in action. As mentioned only the state of the object is kept in the object, but every thing that can be shared will be cloned when a new instance is created. This means the publicField we have will always have the value “public” no matter how many instances of the object you created and if you change the value of it, it will be changed for all existing and new instances. This is the same for the publicFunction and the body of the function, but in the function you are able to access the state of the instance. This way you can write the function signature once, but access and change the state of the instance individually.



   1: function Class(p) {
   2:     var privateField = p;
   3:     function privateFunction() {
   4:         return privateField;
   5:     }
   6:  
   7:     this._privateFunction = privateFunction;
   8: }
   9:  
  10: Class.prototype.publicField = "public";
  11: Class.prototype.publicFunction = function () {
  12:     return this._privateFunction();
  13: };
  14:  
  15: var instance = new Class("private");
  16: alert(instance.publicField); // shows "public"
  17: alert(instance.publicFunction()); // shows "private"

With the above example you can also create a second instance with “public” as argument and in this case the publicFunction will return “public”.


One of the disadvantages of this approach is the fact that all the fields you want to access in the shared functions (defined in the prototype), need to be public on the instance. Meaning they need to be returned or added to the scope. To solve this a bit there is a convention that private fields, who need to be accessible in the shared parts have a “_”-prefix. This won’t make them inaccessible, but intellisense will ignore them, so making it a bit harder to know.


Revealing Prototype Pattern


As you see with the prototype pattern every thing you define as shared is public. This is where the revealing prototype goes further. It allows you to have private functions and variables inside the shared scope.



   1: function Class() {
   2:     var privateField = "private"
   3:     function privateFunction() {
   4:         return privateField;
   5:     }
   6:  
   7:     this._privateFunction = privateFunction
   8: }
   9:  
  10: Class.prototype = function () {
  11:     var privateField = "Hello";
  12:     var publicField = "public";
  13:     function privateFunction() {
  14:         return privateField + " " + this._privateFunction();
  15:     };
  16:  
  17:     return {
  18:         publicField: publicField,
  19:         publicFunction: privateFunction
  20:     };
  21: }();
  22:  
  23:  
  24: var instance = new Class();
  25: alert(instance.publicField); // shows "public"
  26: alert(instance.publicFunction()); // shows "Hello private"

Conclusion


By using the revealing prototype pattern you have several advantages:



  • Less memory use, everything defined as shared is only created once.
  • You have the advantage to encapsulate your private code and expose public only the functions and fields you want
  • The classes are open for extension but closed for modification: you can easily add extra functionality without affecting the existing implementation.

Of course there are some down sizes too:



  • The definition of the constructor and the class implementation (for the prototype parts) are separate
  • You can make your state fully private if you need it in the shared parts.

For me the leverage of the advantages are bigger than the disadvantages. I’m using this pattern more and more. I’m also busy migrating my library to use this pattern, so other people can easily extend my library and add there own functionality without changing the source file and the existing implementation.