Created
March 8, 2012 16:40
-
-
Save jblanche/2001982 to your computer and use it in GitHub Desktop.
Javascript Inheritance and Mixins
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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