Skip to content

Instantly share code, notes, and snippets.

@jblanche
Created March 8, 2012 16:40
Show Gist options
  • Save jblanche/2001982 to your computer and use it in GitHub Desktop.
Save jblanche/2001982 to your computer and use it in GitHub Desktop.
Javascript Inheritance and Mixins
/*
This is a test aiming at creating a simple inheritance + mixin capable JS library
using Object.create awesome possibilities.
It's using a single library (https://raw.github.com/jblanche/proto-js/master/Proto.js)
that is only 609 characters minified, and 310b gzipped.
It is heavily based on the original Proto.JS library (https://github.com/rauschma/proto-js).
Simply adding to it an easy way to add mixins to our "Classes".
*/
// This is a Mixin / Module, it can be included by any "Class", whatever the class role.
// It's a plain and simple JS litteral object.
var Comparable = {
// The Only thing this mixin needs is a "compare"
// method in the Class that includes it.
isGreaterThan : function(other){
return this.compare(other) === 1;
},
isEqualTo : function(other){
return this.compare(other) === 0;
},
isLowerThan : function(other){
return this.compare(other) === -1;
},
isLowerOrEqualTo : function(other){
return this.compare(other) <= 0;
},
isGreaterOrEqualTo : function(other){
return this.compare(other) >= 0;
},
between: function(min, max){
if(this.compare(min) < 0 || this.compare(max) >0){
return false;
}
return true ;
}
};
// This is a Simple Particle class with position (x,y) and a radius.
// Proto.Extend takes a simple litteral object as its only parameter
// Every propertie or method defined in this object will be available on object instances
var Particle = Proto.extend({
// The constructor method is the initializer
// it is called automatically when creating an instance
constructor: function(options){
//Defining main properties
this.x = options.x || 0 ;
this.y = options.y || 0 ;
this.radius = options.radius || 1 ;
},
// this is the Compare method our Comparable mixin will use.
// We are defining that particles are compared based on their radius.
compare: function(other){
if(this.radius > other.radius) return 1 ;
else if(this.radius === other.radius) return 0 ;
else return -1 ;
},
describe: function(){
return "I'm in "+this.x+ " : " + this.y+" , radius: "+this.radius;
}
});
// extend Comparable mixin
extend(Particle, Comparable);
// The ColorParticle is a "SubClass" of Particle "Particle.extend({})"
// No need to redefined "compare" here, if compare is called on a ColorParticle instance
// the Particle "compare" method is in the prototype chain and will be called.
var ColorParticle = Particle.extend({
constructor: function(options){
ColorParticle.super.constructor.call(this, options);
this.color = options.color || "#FFF" ;
},
describe: function(){
return ColorParticle.super.describe.call(this) + " and I'm "+this.color;
}
});
// This is a Person class, not a lot to share with particles...
// But I want People to be comparable too, so lets include comparable there too.
var Person = Proto.extend({
constructor: function (name, height) {
this.name = name;
this.height = height ;
},
// Persons are compared based on their height (Yes I know, this is dumb).
compare: function(other){
if(this.height > other.height) return 1 ;
else if(this.height === other.height) return 0 ;
else return -1 ;
},
describe: function() {
return "Person called "+this.name;
}
});
// extend Comparable mixin
extend(Person, Comparable);
// This is the Employee class, SubClass of the Person one.
// Employee redefines the Person compare method to use salary instead of height.
var Employee = Person.extend({
constructor: function (name, height, salary) {
Employee.super.constructor.call(this, name, height);
this.salary = salary || 0;
},
// Employees are compared based on their salary (Yes I know, this is dumber).
compare: function(other){
if(this.salary > other.salary) return 1 ;
else if(this.salary === other.salary) return 0 ;
else return -1 ;
},
describe: function () {
return Employee.super.describe.call(this)+" (earns $"+this.salary+" a month)";
}
});
// Let's create a few particles and compare them
var particule1 = Particle.new({x:2, y:4, radius:5});
var particule2 = ColorParticle.new({x:5, y:8, radius:10, color: '#CCC'});
var particule3 = ColorParticle.new({x:12, y:4, radius:7, color: '#F0F'});
console.log(particule2.isEqualTo(particule1));
// -> false
console.log(particule2.describe());
// -> I'm in 5 : 8 , radius: 10 and I'm #CCC
console.log(ColorParticle.isPrototypeOf(particule2));
// -> true
console.log(ColorParticle.isPrototypeOf(particule1));
// -> false
console.log(particule3.between(particule1, particule2));
// -> true
// What about persons
var person1 = Person.new('Alice', 164);
var person2 = Person.new('Bob', 180);
console.log(person2.isLowerOrEqualTo(person1));
// -> false
console.log(person2.describe());
// -> Person called Bob
// Or employees
var employee1 = Employee.new('John', 174, 2000);
var employee2 = Employee.new('Jane', 168, 3000);
var employee3 = Employee.new('Jill', 170, 4000);
console.log(employee2.isGreaterThan(employee1));
// -> true
console.log(employee2.describe());
// -> Person called Jane (earns $3000 a month)
console.log(employee3.between(employee1, employee2));
// -> false
// I can even apply some behavior to a single instance
var Teenable = {
describe: function(){return 'LOL XPTDR';}
}
extend(employee3, Teenable);
console.log(employee3.describe());
// -> LOL XPTDR
// other instances are still clean
console.log(employee2.describe());
// -> Person called Jane (earns $3000 a month)
// I can augment classes instances after the creation
// this will even affect previously created instances !
var Serializable = {
serializeToJSON: function(){
return JSON.stringify(this);
}
}
extend(Person, Serializable);
console.log(employee3.serializeToJSON());
// -> {"name":"Jill","height":170,"salary":4000}​​​​​
name: Javascript Inheritance and Mixins
description: How to use Inheritance and Mixins in current JS
authors:
- Jonathan Blanchet
resources:
- https://raw.github.com/jblanche/proto-js/master/Proto.js
normalize_css: no
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment