Peter Leonov's Blog

Native inheritance in JavaScript

06 April 2011

Inheritance without a framework leads to panic attack even those who are experienced JS coders. Especially if it's needed to not just add more methods but also modify existing ones (dont ask why, it's ruthless OOP). But it is so simple (trollface).

Simple class #

function A () {}

var a = new A()

Yeap, a class in JS is just a function.

Anonymous class #

var o = new function () {}

Any function could be a class even a anonymous lambda.

A class with a method #

function A () {}
A.prototype =
{
	method: function () {}
}

var a = new A()
a.method()

In strict OOP methods get added with prototypes. Yes those guys prototypes.

“Static” method #

function A () {}
A.staticMethod = function () {}
A.staticMethod()

staticMethod is not available in instances.

Inheritance in outer space #

function A () {}


function B () {}
B.prototype = new A()

Yes, exactly prototype = new A(), not just prototype = A().

Not a useless inheritance #

function A () {}
A.prototype =
{
	methodA: function () {}
}


function B () {}
B.prototype = new A()

var b = new B()
b.methodA()

Here we have in class B a useful methodA() from class A.

Adding a method #

function A () {}
A.prototype =
{
	methodA: function () {}
}


function B () {}
B.prototype = new A()
B.prototype.methodB = function () {}

var b = new B()
b.methodA()
b.methodB()

Now instances of class B has two handy methods one from A and one from B.

Adding lots of methods #

function A () {}


function B () {}
B.prototype = new A()

var methodsB =
{
	methodB1: function () {},
	methodB2: function () {},
	methodB3: function () {}
}

Object.extend(B.prototype, methodsB)

var b = new B()
b.methodB1()
b.methodB2()
b.methodB3()

Object.extend(dst, src) just copies properties from src to dst. If you doctor allows you may replace Object.extend() with for in loop ;)

Replacing a mwthod #

function A () {}
A.prototype =
{
	methodA: function () {}
}


function B () {}
B.prototype = new A()
B.prototype.methodA = function () { alert(42) }

var b = new B()
b.methodA()

Alert window shows here.

Constructive inheritance #

function A ()
{
	this.array = []
}


function B ()
{
	A.apply(this)
}
B.prototype = new A()

var b1 = new B()
var b2 = new B()
console.log(b1.array == b2.array)
//>>> false

If A.apply(this) would not get called, then all instances of B share the same array.

Simple super method #

function A () {}
A.prototype =
{
	methodA: function () {}
}


function B () {}
B.prototype = new A()

B.prototype.superMethodA = B.prototype.methodA
B.prototype.methodA = function ()
{
	this.superMethodA()
}

var b = new B()
b.methodA()

Perfectly fine for simple cases.

More sophisticated super method #

function A () {}
A.prototype =
{
	methodA: function () {}
}


function B () {}
B.prototype = new A()

B.prototype.methodA = function ()
{
	A.prototype.methodA.apply(this)
}


function C () {}
C.prototype = new B()

C.prototype.methodA = function ()
{
	B.prototype.methodA.apply(this)
}

var c = new C()
c.methodA()

Just always works.

Faster supermethod #

function A () {}
A.prototype =
{
	methodA: function () {}
}


function B () {}
B.prototype = new A()

var superMethodA = A.prototype.methodA
B.prototype.methodA = function ()
{
	superMethodA.apply(this)
}

var b = new B()
b.methodA()

Performs better, but breaks if A.prototype gets changed.

Useful super method #

function A () {}
A.prototype =
{
	setPosition: function (x)
	{
		this.x = x
	}
}


function B () {}
B.prototype = new A()

B.prototype.setPosition = function (x, y)
{
	A.prototype.setPosition.call(this, x)
	this.y = y
}


function C () {}
C.prototype = new B()

C.prototype.setPosition = function (x, y, z)
{
	B.prototype.setPosition.call(this, x, y)
	this.z = z
}

var c = new C()
c.setPosition(1, 2, 3)

In result of a hidden sequential call of A#setPosition() and B#setPosition() inside C#setPosition(), we get and object with data {x: 1, y: 2, z: 3}.

Tags:
  • frontend
  • javascript
  • frameworkless