Friday, March 1, 2013

Javascript Prototypal Inheritance


Javascript's prototypal inheritance can be tough to wrap you head around, but I think an easy way to think about prototype and __proto__ is the following:

When you create a new object you would say
var bob = new WorkerBee();
given the following definition of WorkerBee as
function WorkerBee (projs) {
  this.projects = projs || [];
}
WorkerBee.prototype = new Employee;

function Employee (name, dept) {
  this.name = name || "";
  this.dept = dept || "general";
}

When you see the above code you may think what would happen if you forgot to instantiate a new Employee when you set WorkerBee's prototype.
aka WorkerBee.prototype = Employee;
Well lets try it out, first off you will see that you can no longer access variables set in Employees constructor
so bob.name or dept will be undefined
also you will notice that bob will not be an instanceof Employee anymore since you broke the inheritance chain by not saying new Employee

Some Notes are below to convince your self further of your understanding of prototype and __proto__.


function Ninja(){}

Ninja.prototype.swingSword = function(){
  return true;
};

var ninjaA = Ninja();
assert( !ninjaA, "Is undefined, not an instance of Ninja." );

var ninjaB = new Ninja();
assert( ninjaB.swingSword(), "Method exists and is callable." );

http://ejohn.org/apps/learn/#65

var ninja = (function(){
 function Ninja(){}
 return new Ninja();
})();

// Make another instance of Ninja
var ninjaB = new ninja.constructor();

assert( ninja.constructor == ninjaB.constructor, "The ninjas come from the same source." );

http://ejohn.org/apps/learn/#74

Quick test of prototypes

car instanceof Vehicle
false
Vehicle.prototype.isPrototypeOf(car);
false
Car.prototype = new Vehicle;
Vehicle
Vehicle.prototype.isPrototypeOf(car);
false
car instanceof Vehicle
false
car = new Car;
Car
Vehicle.prototype.isPrototypeOf(car);
true
car instanceof Vehicle
true

-------------
function Blah() {}
> Blah.prototype
Blah
> Blah.prototype.constructor
function Blah() {}
> Blah.prototype.constructor.__proto__
function Empty() {}
> Blah.prototype.constructor.__proto__.constructor
function Function() { [native code] }
> Blah.prototype.constructor.__proto__.constructor.prototype
function Empty() {}
> Blah.prototype.constructor.__proto__.constructor.prototype.constructor.prototype
function Empty() {}

http://i.imgur.com/IkxPv.png

http://stackoverflow.com/questions/650764/how-does-proto-differ-from-constructor-prototype
http://www.klauskomenda.com/code/javascript-inheritance-by-example/



Determining instance relationships

Property lookup in JavaScript looks within an object's own properties and, if the property name is not found, it looks within the special object property __proto__. This continues recursively; the process is called "lookup in the prototype chain".
The special property __proto__ is set when an object is constructed; it is set to the value of the constructor's prototype property. So the expression new Foo() creates an object with __proto__ == Foo.prototype. Consequently, changes to the properties of Foo.prototype alters the property lookup for all objects that were created bynew Foo().
Every object has a __proto__ object property (except Object); every function has a prototype object property. So objects can be related by 'prototype inheritance' to other objects. You can test for inheritance by comparing an object's __proto__ to a function's prototype object. JavaScript provides a shortcut: the instanceof operator tests an object against a function and returns true if the object inherits from the function prototype. For example,
1
2
var f = new Foo();
var isTrue = (f instanceof Foo);
For a more detailed example, suppose you have the same set of definitions shown in Inheriting Properties. Create an Engineer object as follows:
1
var chris = new Engineer("Pigman, Chris", ["jsd"], "fiji");
With this object, the following statements are all true:
1
2
3
4
5
chris.__proto__ == Engineer.prototype;
chris.__proto__.__proto__ == WorkerBee.prototype;
chris.__proto__.__proto__.__proto__ == Employee.prototype;
chris.__proto__.__proto__.__proto__.__proto__ == Object.prototype;
chris.__proto__.__proto__.__proto__.__proto__.__proto__ == null;
Given this, you could write an instanceOf function as follows:
1
2
3
4
5
6
7
8
9
10
11
function instanceOf(object, constructor) {
   while (object != null) {
      if (object == constructor.prototype)
         return true;
      if (typeof object == 'xml') {
        return constructor.prototype == XML.prototype;
      }
      object = object.__proto__;
   }
   return false;
}


https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Details_of_the_Object_Model

1 comment: