Skip to content
PhoenixAndMachine edited this page Apr 7, 2014 · 2 revisions

Inheritance

There are three ways to achieve inheritance in Javascript. The key is to play with prototype. Before reading these code, it is better for you to understand prototype chain in JS, and the differences between prototype and __proto__.

Classical Inheritance

/* Extend function */

function extend(subClass, superClass) {
	var F = function(){};
	F.prototype = superClass.prototype;
	subClass.prototype = new F();
	subClass.prototype.constructor = subClass;

	subClass.superclass = superClass.prototype;
	if(superClass.prototype.constructor==Object.prototype.constructor) {
		superClass.prototype.constructor = superClass;
	}
}

/* Person */

function Person(name, age) {
	this.name = name;
	this.age = age;
}

Person.prototype.getName = function() {
	return this.name;
}

Person.prototype.getAge = function() {
	return this.age;
}

/* Author */

function Author(name, age, books) {
	Author.superclass.constructor.call(this, name, age);
	this.books = books;
}
extend(Author, Person);

Author.prototype.getBooks = function() {
	return this.books;
}

Author.prototype.getName = function() {
	var name = Author.superclass.getName.call(this); // be able to call methods of superclass
	return name + ', Author of ' + this.getBooks().join(', ');
}

/* Usage */
var bart = new Author('Bart Van lierde', 38, ['Zot van A']);

console.log("----------------bart can call its own properties--------------");
console.log(Object.getOwnPropertyNames(bart)); // [ 'books', 'name', 'age' ]
console.log("----------------bart is an instance of Author-----------------");
console.log(bart instanceof Author); // true
console.log(bart.__proto__===Author.prototype); // true
console.log("----------------bart can call Author's methods(improved)----------------");
console.log(Author.prototype); 
/*
	Output
		{ 
			constructor: { [Function: Author] superclass: { getName: [Function], getAge: [Function] } },
		  	getBooks: [Function],
		  	getName: [Function] // overwritten in Author.prototype.getName
		}
*/

console.log("----------------bart is an instance of Person-----------------");
console.log(bart instanceof Person); // true

console.log("----------------bart can call Person's methods--------------");
console.log(bart.__proto__.__proto__); // { getName: [Function], getAge: [Function] }


console.log(bart.getName());

Prototypal Inheritance

/* Clone function */

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

/* Composite Object */

var configuration = {
	name: 'default name',
}

configuration.display = function() {
	console.log("Name: " + this.name);
	console.log("limit_package: " + this.details.limit_package);
	console.log("bandwidth: " + this.details.bandwidth);
}

/* method for creating child object */

configuration.createDetails = function() {
	return {
		limit_package: 'default limit package',
		bandwidth: 'default bandwidth'
	}
}

configuration.details = configuration.createDetails();

var cf1 = clone(configuration);
var cf2 = clone(configuration);
cf1.details = configuration.createDetails();
cf1.details.bandwidth = 'cf1 bandwidth';


console.log("---------configuration---------");
configuration.display();
console.log("--------------cf1--------------");
cf1.display();
console.log("--------------cf2--------------");
cf2.display();

Partial Inheritance


/* Mixin Class */

var Mixin = function() {};

Mixin.prototype = {
	serialize: function() {
		var output = [];
		for(key in this) {
			output.push(key + ':' + this[key]);
		}
		return output.join(', \n');
	},
	useless: function() {
		console.log("USELESS FUNCTION");
	}
}


/* Augment function with improvement */

function augment(receivingClass, givingClass) {

	if(arguments[2]) {
		for (var i=2, length=arguments.length; i<length; i++) {
			if(!receivingClass.prototype[arguments[i]]) {
				receivingClass.prototype[arguments[i]] =givingClass.prototype[arguments[i]];
			}
		};
	}
	else {
		for(methodName in givingClass.prototype) {
			if(!receivingClass.prototype[methodName]) {
				receivingClass.prototype[methodName] = givingClass.prototype[methodName];
			}
		}
	}
}


/* Usage */

function Person(name, age) {
	this.name = name;
	this.age = age;
}

Person.prototype.getName = function() {
	return this.name;
}

Person.prototype.getAge = function() {
	return this.age;
}

augment(Person, Mixin, 'serialize');

var p = new Person('Einstein', 38);

console.log(p.serialize());

Clone this wiki locally