Monthly Archives: December 2012

Simple JavaScript Inheritance

I have read quite a few posts on JavaScript inheritance. They all seem quite involved, and some are very complicated to implement. I took a crack at it, and this is what I came up with.

Here are a few advantages to this simple JavaScript inheritance:

  • Simple :)
  • Use the same pattern to instantiate new objects.
  • Supports “private” variables, functions
  • Supports “public” (“privileged”) variables, functions
  • Support “abstract” functions (sort of)

Methodology. All I’m doing is combining objects. I wrote an “extend” method that recursively combines objects together, and use it to combine the “this” variable inside a function with another object.

First thing, include this function somewhere in your code. This is the the secret sauce, the thing that makes it all possible (There’s actually nothing special about this method. You can use pretty much any “extend” method you like, like jQuery.):

function Extend(a) {
	if(typeof a != 'object')
		return false;
	function appendRecursively(a, b) {
		if(typeof a != 'object' || typeof b != 'object')
			return false;
		for(var i in b) {
			if(appendRecursively(a[i], b[i]))
				continue;
			a[i] = b[i];
		}
		return true;
	}
	for(var i in arguments) {
		if(i == 0)
			continue;
		appendRecursively(a, arguments[i]);
	}
	return a;
}

I can’t think of a better way to describe it than show you some code. Pay particular attention to the calls to “Extend” method. (See it on jsfiddle)

var Parent = function(o) {
	var self = this; // jump scope
	this.publicVariable = 'P publicVariable'; // public (privileged) variable
	var privateVariable = 'P privateVariable'; // private variable
	this.publicMethod = function() {
		output(self.publicVariable); // has access to public variables, methods
		output(privateVariable); // has access to private variables
		privateMethod(); // has access to private methods
	}
	this.getPrivateVariable = function() {
		return privateVariable;
	}
	var privateMethod = function() {
		output(self.publicVariable, privateVariable); // has access to public, private variables, methods.
	}
	this.abstractMethod = function() { // this is the closest thing JavaScript has to an abstract method
		throw 'abstractMethod() is not defined';
	}

	Extend(this, o); // simple instantiation
	return this;
}

// ** this is all you really need for inheritance.
var Child = function(o) {
	var child = new Parent(Extend(this, o)); // simple inheritance
	return child;
}

var GrandChild = function(o) {
	this.helloWorld = function(name) {
		return 'Hello, '+name+'.';
	}
	var grandChild = new Child(Extend(this, o)); // simple inheritance
	return grandChild;
}

var GreatGrandChild = function(o) {
	this.publicVariable = 'GGC publicVariable'; // override the variable set in Parent
	this.publicMethod = function() {
		return privateMethod();
	}
	var privateMethod = function() {
		return 'GGC privateMethod';
	}
	this.abstractMethod = function() {
		return 'GGC Abstract Method';
	}

	var greatGrandChild = new GrandChild(Extend(this, o)); // simple inheritance

	output(greatGrandChild.getPrivateVariable()); // has access to all parent's public methods, variables
	output(greatGrandChild.helloWorld('Great Grand Child'));

	return greatGrandChild;
}

output('_PARENT_');
var P = new Parent();
P.publicMethod();

output('_GRAND CHILD_');
var GC = new GrandChild({
	publicMethod: function() {
		return 'GC publicMethod';
	},
	abstractMethod: function() {
		return 'GC Abstract Method';
	}
});
output(GC.publicMethod());
output(GC.abstractMethod());

output('_GREAT GRAND CHILD_');
var GGC = new GreatGrandChild();
output(GGC.publicMethod());
output(GGC.abstractMethod());

// ** this is how you could use this inheritance model for simple object instantiation.
var InstantiatedObject = new Parent({
	abstractMethod: function() {
		return 'GC Abstract Method';
	}
});

function output(str) {
	console.log(str);
}

/*

Console Output:

_PARENT_
P publicVariable
P privateVariable
P publicVariable P privateVariable
_GRAND CHILD_
GC publicMethod
GC Abstract Method
_GREAT GRAND CHILD_
P privateVariable
Hello, Great Grand Child.
GGC privateMethod
GGC Abstract Method

*/

(See it on jsfiddle)

Don’t like the way I did it? That’s okay. Here are a handful of other ways: