Picture

Hi, I'm Boopathi Rajaa.

Hacker, Dancer, Biker, Adventurist

Prototyping and GC advantages in JavaScript

It is a common practice to use patterns, like the one mentioned below, by most of the JavaScript programmers.

Note: Whenever I mention class , or any OO terms in this post, it just means that we are simulating Object Orientation. You cannot write proper OO code in JavaScript. Just presume it to be a class while reading through, for better understanding.

    //Defining base class - foo
    var foo = function (attr) {
        var self = new Object();
        self.get = function() { return attr; };
        self.set = function(val) { attr = val; };
        return self;
    }
    var f1 = foo("lorem");
    var f2 = foo("ipsum");

And when you want to espouse inheritance, this schema becomes prettier, allowing you to scale out and scale up programmatically.

    //Extending class foo to bar
    var bar = function(attr){
        var self = foo(attr); //parent
        self.greet = function(){ return "Welcome " + attr; };
        return self;
    }
    var b1 = bar("sample");

Now this type of inheritance in JavaScript is coined as functional pattern as explained by Douglas Crockford in his book - JavaScript - The Good Parts. By this way, any type inheritance is possible.

Analysis

Whenever you invoke the function foo or bar, two or three new functions are created. Consider the statement var x = foo("test") , a new Object of type Object is created within the namespace of x. And two more functions are created within that Object's namespace. This happens for every Object that is created from foo , and each time, the functions are basically the same, but they are bound to different values. And you can see that each entity becomes a closure that maintains a reference for every named variable in the enclosing function within which the closure was defined. And we unintentionally prevent the JavaScript engine from Garbage Collecting these Objects, which apparently causes a memory leak.

Why should a JavaScript programmer worry about Garbage Collection ?

Prerequisite: http://en.wikipedia.org/wiki/Garbage_collection_(computer_science)

The main purpose of Garbage Collection is to allow the programmer NOT to worry about the memory management of the objects they create and use. Like in C, C++, we don't allocate memory in JavaScript. Memory is allocated whenever you define a new function, or create a new Object. As a rule of thumb, memory blocks get gobbled up whenever the engine sees a new, var or function (or closure) . JavaScript is a queer creature, that, the functions are Objects, arrays are Objects, and of-course objects are Objects :P. When we create objects, we really are allocating memory. Only, we are not doing that explicitly. We can indeed allocate an array, and use it like a memory buffer, but JavaScript was not designed to be used that way. Using it that way will simply degrade the engine's performance. At some places, the engine's Garbage Collector comes to the rescue by taking care of cleaning it all up. When a block of memory (or Object) is no longer reachable, it is eligible to be reclaimed. When, how and whether it is reclaimed is completely up to the implementation. But at a language level, it is automatic. As usual, let us consider an example.

    //Poor code
    var x = function () {
      var y = new SomeBigObject();
      setTimeout(function () {
        console.log("hi");
      }, 10000);
    }

Whenever x is invoked, the big guy is not available for garbage collection immediately when x returns. This is because, the timer guy has a reference to the anonymous function we've created, and the anonymous function has a reference to the execution context created for the call to x, which includes the big guy, and so y continues to the reference the big guy. After 10 seconds, when the timer releases the anonymous function, which is then available to be garbage collected, as is anything the anonymous function was referencing. So the execution context containing y and object y are now available to be garbage collected.

Consider a case, where there is no timer in the function definition of x. Here the big guy is automatically available for garbage collection because there is nothing left that has a reference to it. And in a case where we return y from x, the big guy still holds a reference, and survives the call. He persists until y is reassigned or y goes out of scope.

Now for the good part, the engine handles and has no problem cleaning up circular references a.x = b; b.y=a . Hope the explanation suffices the need for the programmer to know about Garbage Collection in JavaScript.

Prototype based inheritance

Now, lets get back to where we started - the discussion about the cons of functional pattern in JavaScript. In the view of providing the same functionality with scaling opportunities, when we define foo like this,

    //base class
    var foo = function (attr) {
      this.attr = attr;
    }
    foo.prototype.get = function () {
      return this.attr;
    }
    foo.prototype.set = function (val) {
      this.attr = val;
    }
    //inherited from foo
    var bar = function(attr) {
      this.p = foo.apply(this, [attr]);
      this.attr = attr;
    }
    bar.prototype.greet = function () { return "welcome" + attr; }

it doesn't become a concern when foo is called because of how it takes advantage of the prototype-based inheritance. Each method is defined only once in the prototype chain and is available to every execution context objectized from foo. This limits the number of function objects that are created and does not risk the leaking of memory.