12 Şubat 2015 Perşembe

Nodejs Inheritance

I will give an example on how inheritance can be applied in JavaScript and Node.js. This post does not cover the topic in its entirety, but explains crucial points.

It is tested with node 0.6.12 on Ubuntu 12.04

1. Prototype Chain

When it comes to inheritance, JavaScript only has one construct: objects. Each object has an internal link to another object called its prototype. That prototype object has a prototype of its own, and so on until an object is reached with null as its prototype. null, by definition, has no prototype, and acts as the final link in this prototype chain. In addition to this, every object has Object.prototype (prototype of Object) in its prototype chain.
An object inherits methods and properties in its prototype chain. This also implies that all objects inherit methods and properties of Object.prototype.

1.1. Property Access

Functions and variables are both treated same way as properties. When it is attempted to access a property of an object, this property is looked up in object's own properties.  If the property is not found directly in the object, it is looked up in its direct prototype. If it is not in the direct prototype, it is looked up in second prototype in the chain.  Until a null prototype is found, this traversal continues. Usage of this in a function in an object's prototype does not refer to prototype but inheriting object.

These has following implications
  • Properties can be shadowed:When a object redefines a property (function, variable etc.), it shadows the property down in its prototype chain. 
  • This property shadowing can be used as a method overriding mechanism.
  • Resolution of this to inheriting object also provides method overriding rules similar to Java method invocation rules.
1.2. prototype, __proto__, Object.getPrototypeOf
prototype is used with types whereas __proto__ or Object.getPrototypeOf() is used for instances.

var a1 = new A();
var a2 = new A();
A.prototype == Object.getPrototypeOf(a1) == Object.getPrototypeOf(a2) == a1.__proto__ == a2.__proto__

2. Example

In following example, super class -if we use OO terms- will have 2 methods and sub class will override one method.

function SuperClass(name){
  this.name = name;
}

SuperClass.prototype = {
  /**
 * Validate the request
 * Default : true
 */
 validateRequest : function(input, callback){
  console.log("Validating the request: ", input);
  callback(null, true);
 },
 /**
 * 1. Validate the request
 * 2. Reply with response
 */
 process : function(input, callback){
  var self = this;
  console.log("Processing the request");
  self.validateRequest(input, function(err, result){
   if(err){
    console.log("Error when validating the request: ", err);
    callback(err);
   }

   if(result == true){
    console.log("Validated!")
    callback(null, "OK");
   }else{
    console.log("Validation failed!")
    callback(null, "FAIL");
   }
  });
 }
}

function SubClass(){
 SuperClass.call(this, "Greater Than Test");
}

SubClass.prototype = Object.create(SuperClass.prototype, {
    validateRequest : {
      value: function(request, callback){ // override
         console.log("Validating request...");
         if(request > 10){
          callback(null, true);
         }else{
          callback(null, false);
         }
         
      },
      enumerable: true,
      configurable: true,
      writable: true
    }
});

var sub = new SubClass();
console.log(SuperClass.prototype);
console.log(SubClass.prototype);
sub.process(15, function(err, result){
 console.log(result);
});


> node inheritance.js 
{ validateRequest: [Function], process: [Function] }
{ validateRequest: [Function] }
Processing the request
Validating request...
Validated!
OK


The important points are:

  • SubClass constructor uses call method to run the constructor of  SuperClass. Usage of this comes from the requirements of call method.
  • Object.craete() method enables us to assign SuperClass.prototype to the prototype chain of SubClass. In other words, SubClass prototype assigns SuperClass.prototype as its upper prototype
  • Call to sub.process() calls function in SuperClass and than calls SubClass's validateRequest method
  • Super class implementation of validateRequest function can be used by adding below to overriding method.
SuperClass.prototype.validateRequest.call(this, request, callback);




Further Reading

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Inheritance_and_the_prototype_chain
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Inheritance_Revisited
http://book.mixu.net/node/ch6.html

Hiç yorum yok:

Yorum Gönder