JavaScript’s prototypal inheritance

In our current project we are using JavaScript for a component which should be deployed on iOS, Android and also on server side. JavaScript is a quite facinating language because it hides its true functional nature quite well and provides gotchas which traps the unwary.

In 2008, I’ve read the book “JavaScript – The good parts” from Douglas Crockford. In chapter 3 the beget method is introduced, which creates a new function with a given prototype:

if (typeof Object.beget !== 'function') {
   Object.beget = function(o) {
      var F = function() {};
      F.prototype = o;
      return new F();
    }
}

The advantages of the beget method:

  • The prototype chain is setup correctly
  • The programmer doesn’t have to use the new keyword in order to create a new object.

But why could the new keyword be so dangerous ?

If the programmer ommits the new keyword when calling a constructor function, no object will be created. Instead undefined will be returned. In addition the global context might be polluted, because the global context will become the invocation context (also known as this variable). The following example shows what happens when new is ommitted:

var Product = function(id) {
   this.id = id;
}

var p = Product(3);
console.log(p);  // --> undefined
console.log(id); // --> 3

So, the beget method prevents these errors and embraces prototypal inheritance. But there is an alternative: John Resig (and also others) presented a way to support pseudo-classical inheritance in JavaScript. I thought about to use it, but I came to the conclusion that it seems to be quite overengineered for our project. In addition the JavaScript community discussed the pseudo-classical inheritance controversial. Douglas Crockford wrote on his website:

The “super” idea is fairly important in the classical pattern, but it appears to be unnecessary in the prototypal and functional patterns. I now see my early attempts to support the classical model in JavaScript as a mistake.

In a comment on his own blog, John Resig sums it up quite well:

The usefulness of one method vs. another is debatable. If you’re just doing simple stuff then just use straight prototypal inheritance – there’s no reason to have any extra overhead. However when it comes time to stuff like super methods you’ll need some construct to make it happen.

So I wanted to use this beget method in my JavaScript code to use prototypal inheritance. But then I’ve found out, that this method found its way into the language itself as Object.create. Great 🙂

If you want to dig further into the prototype chain, consider the excellent book “You Don’t Know JS: this & Object Prototypes“.

Private Methoden in JavaScript dank Closures

Momentan lese ich das Buch “JavaScript: The Good Parts” von Douglas Crockford. Ein durchweg empfehlenswertes Buch, das eine klare und kompakte Übersicht über die Stärken (und Schwächen) von JavaScript bietet. Sehr interessant ist das “Functional”-Pattern: Mit Hilfe von Closures können private Instanzvariablen und Methoden definiert werden. In 4 Schritten erstellt eine sogenannte “Maker”-Methode eine neue Objekt-Instanz.

  1. Erzeuge ein neues Objekt
  2. Definiere in der Methode die (privaten) Instanzvariablen und Methoden.
  3. Hänge an das neue Objekt die öffentlichen Methoden. Dank dem “Closure”-Prinzip haben nur diese Methoden Zugriff auf die vorher definierten Instanzvariablen und Methoden.
  4. Gebe das neue Objekt zurück.
  5. Hier das Beispiel:

    1. var vehicle = function(spec) {
    2.      // the spec object contains all attributes needed to create the object.
    3.      
    4.      // create a new empty object using the object literal
    5.      var o = {};    
    6.  
    7.      // vars of this function are the private variables of the new object
    8.      var age            = 0;    
    9.      var maxSpeed       = spec.maxSpeed;
    10.      var name           = spec.name;
    11.      var price      = spec.price;
    12.          
    13.      // private methods
    14.      var calculateDegradation = function() {
    15.            return age * price / 10 ; // assuming linear degradation
    16.      };    
    17.  
    18.      // public methods
    19.      o.getName = function() {
    20.          return name;
    21.      };
    22.  
    23.      o.getMaxSpeed = function() {
    24.          return maxSpeed;
    25.      };
    26.  
    27.      o.setAge = function(v) {
    28.         age = v;
    29.         return o; // cascade pattern
    30.      }
    31.    
    32.      o.getResidualValue = function() {
    33.          return price - calculateDegradation();
    34.      };
    35.  
    36.      return o;
    37. }
    38.  
    39. var myVehicle = vehicle( { name: 'Audi R8',
    40.                                 price: '106400',
    41.                                 maxSpeed: '301'});
    42.  
    43. alert(myVehicle.getMaxSpeed()); // 301
    44. alert(myVehicle.getResidualValue()); // 106400;
    45. alert(myVehicle.setAge(2).getResidualValue()); // 85120;

    Interessant ist die Ansicht im Firebug: Keine Spur von den privaten Methoden oder Instanzvariablen. Sie werden durch das “Closure” geschützt.

    myVehicle Ansicht im Firebug zeigt nur die öffentlichen Methoden.