Posts Tagged ‘inheritance’

Prototypal inheritance

Tuesday, September 15th, 2009

Here's the prototypal inheritance pattern suggested by Douglas Crockford.

The implementation looks similar to a classical pattern but the idea is very different.

The idea is that thereís no constructors involved that lead you to think in terms of classes.
You have an object and you want to create another object that gets functionality from the existing object.

And, unlike when we simply copied properties over from the parent, here we involve the prototype and keep the prototype chain.

function object(o) {
  function F(){}
  F.prototype = o;
  return new F();
}

We take an existing object o, create a blank constructor function and set the parent object o to be the prototype.

Then return an object created with the temporary constructor. This child object has all properties of the parent as part of the prototype.

And hereís an example usage:

>>> var parent = {a: 1};
>>> var child = object(parent);
>>> child.a;
1
>>> child.hasOwnProperty(a);
false

The child object has everything the parent has - not as its own properties but as properties of its prototype.

ECMAScript 5

In the proposed version 5 of the ECMAScript standard, there will be a method that will work similarly and also accept another object, so basically you'll be able to inherit and add more functionality at the same time.

var child = Object.create(parent, {more:1})

Classical inheritance

Tuesday, September 15th, 2009

Let's talk a bit about classical inheritance. The word "classical" is not used in the sense of old-school middle-age has-been-around forever kind of meaning.

Classical just means that you think in terms of classes. Your objects are created by constructor functions and you want objects created from one constructor Child() to get properties that come from another constructor Parent().

function Parent(){
  this.name = 'Adam';
}
Parent.prototype.say = function(){
  return this.name;
};
 
function Child(){}

So we call a function called inherit() and letís see some patterns for implementing this function.

inherit(Child, Parent);

Option #1 - The ECMA way

Here's the ECMA standard way. You create an object using the Parent() and assign this object to the Child()'s prototype.
Than when you do new Child(), it will get functionality from the Parent() instance via the prototype.

function inherit(C, P) {
  C.prototype = new P();
}

This pattern has the drawback that itís tough to pass arguments to the parent during the call to new Child()

Option #2 - Rent-a-constructor

This next pattern solves the problem of passing arguments. It borrows the parent constructor passing the child object to be bound to this and passing any arguments.

This way you can only inherit properties added to this inside the parent constructor.
You don't inherits stuff that was added to the prototype.

function C(a, c, b, d) {
  P.call(this, arguments);
}

Option #3 - rent + prototype

Combining the previous two patterns you can pass arguments by borrowing the constructor and also inherit from the prototype.

function C(a, c, b, d) {
  P.call(this, arguments);
}
C.prototype = new P();

Drawback is that the parent constructor is called twice.

Option #3

Here's another way to do classical inheritance that doesn't include calling the parent constructor at all.

The rule of thumb is that reusable stuff should go to the prototype.

So for inheritance purposes, anything interesting should be in the prototype. Can you just say that childís is the parentís prototype? Yes, you can.

function inherit(C, P) {
  C.prototype = P.prototype;
}

This gives you really short prototype chain lookups because everybody has the same prototype. But thatís also a drawback because if a child down the inheritance chain modifies the prototype, it affects all parents.

Option #5

This next pattern solves the same-prototype problem by breaking the direct link and benefiting from the prototype chain.

Here you have an empty function which gets the prototype of the parent. The prototype of the child is an instance of the blank function.

function inherit(C, P) {
  var F = function(){};
  F.prototype = P.prototype;
  C.prototype = new F();
}

This pattern has a behavior slightly different from the ECMA standard suggestion because here you only inherit properties of the prototype. And thatís fine, actually preferable. Like I said Ė the prototype is the place for reusable functionality. Anything the parent ads to this inside the constructor is ignored.

Option #5 + super

Building on top of the previous pattern, you can add a reference to the original parent. This is like having access to the superclass in other languages.

The property is called uber because super is a reserved word and superclass may lead the non-suspecting developer down the path of thinking that JavaScript has classes. And we donít want that, right?

function inherit(C, P) {
  var F = function(){};
  F.prototype = P.prototype;
  C.prototype = new F();
  C.uber = P.prototype;
}

Option #5 + super + constructor reset

One last thing to do in this almost perfect classical inheritance function is to reset the pointer to the constructor function in case we need it down the road.

function inherit(C, P) {
  var F = function(){};
  F.prototype = P.prototype;
  C.prototype = new F();
  C.uber = P.prototype;
  C.prototype.constructor = C;
}

If you donít reset the constructor pointer, objects created with the Child() constructor will report that they were created with the Parent() constructor.

A function like this exists in the YUI library and helps you with your classical inheritance needs.

Mixins

Tuesday, September 15th, 2009

Taking the idea of inheritance by property copying a step further, consider this this mixin implementation.

Instead of copying from one object, you can copy from any number of objects.

The implementation is pretty simple - just loop through arguments and copy every property of every object passed to the function.

function mixInThese() {
  var arg, prop, child = {};
  for (arg = 0; arg < arguments.length; arg++) {
    for (prop in arguments[arg]) {
      child[prop] = arguments[arg][prop];
    }
  }
  return child;
}

Here's how to use it. Pass any number of objects and you and up with a new object that has the properties of them all.

var cake = mixInThese(
 {eggs: 2, large: true}, 
 {butter: 1, salted: true}, 
 {flour: "3 cups"},
 {sugar: "sure!"}
);

Inheritance by copying properties

Monday, September 14th, 2009

Let's take a look at an inheritance pattern Ė inheritance by copying properties. In this pattern an object gets functionality from another object, simply by copying it.

function extend(parent, child) {
  var i, child = child || {};
  for (i in parent) {
    child[i] = parent[i];
  }
  return child;
}

In this implementation child is optional, if you don't pass an existing object to augmented, than a brand new is created and returned.

It's a very simple implementation, just looping through the parentís members and copy them over.

Now you may say "Hey, hey, hey, what about performance? Isnít it inefficient to copy around properties like this?". Technically yes, but if thatís your performance bottleneck, you probably have the fastest JavaScript app ever.

This works for many applications, Firebug has an extend() methods that does this. Firebug is a pretty complex app and this works for it, so it should work for many other applications.

And one more heads-up - this is a "shallow copy" of the object, if you need you can do a "deep copy" - checking if the property you're about to copy is an object and if so, recursively iterate through the properties.

A case against inheritance

Monday, September 14th, 2009

Provocative title, right? Good. The point is not that inheritance is all that bad, it's that you should stop and think or a moment before you jump into long inheritance chains and complex UML.

In fact, the Object-Oriented Design Patterns book from "the gang of four" has this to say about inheritance:

ďPrefer object composition to class inheritanceĒ

Itís pretty easy to follow this advice in JavaScript. Remember - no classes in JavaScript. And how about the object literal, how simple it is? If you can add functionality to your objects from elsewhere Ė why do you need inheritance.

You can start with a blank slate and add stuff Ė either implement it yourself or grab from someone else.

Keep your eyes on the prize. You donít need inheritance, you need functionality. In other languages inheritance may be your only choice. Not in JavaScript.

Further blog posts will show patterns such as borrowing methods, copying properties, mixins...

Doug Crockford on inheritance

Tuesday, May 6th, 2008

JavaScript, the good parts

From YUI blog today, there is a free chapter of Douglas Crockford's JavaScript book.

It's a great read. I had the pleasure of reading drafts of the book and giving some inputs (Whoa, giving Doug Crockford input with his JavaScript book! Yeah, I know.) and I can only highly recommend the book. But don't take my word for it, go download the free chapter and decide for yourself.