Ruby's Open Classes and Inheritance in JavaScript
Using the compact extend function to simulate class-based inheritance in JavaScript we have many of the same features of Ruby classes. One important feature is that classes remain open and that changes in the superclass are automatically also in the subclass. Through the extend function's natural chaining of prototypes we can have this open and inheritable changes. Below are the Ruby and JavaScript versions of the same example to show this at work.
Ruby
class Person
def initialize(first, last)
@first = first
@last = last
end
def to_s
@first + ' ' + @last
end
end
class Employee < Person
def initialize(first, last, id)
super(first, last)
@id = id
end
def to_s
super + ': ' + @id.to_s
end
end
peter = Employee.new('Peter', 'Michaux', 3)
puts peter # Peter Michaux: 3
# open the Person class and add a new method
class Person
def reverse_name
@last + ', ' + @first
end
end
puts peter.reverse_name # Michaux, Peter
JavaScript
var Class = {
extend: function(subclass, superclass) {
function D() {}
D.prototype = superclass.prototype;
subclass.prototype = new D();
subclass.prototype.constructor = subclass;
subclass.superclass = superclass;
subclass.superproto = superclass.prototype;
}
};
function Person(first, last) {
this.first = first;
this.last = last;
}
Person.prototype.toString = function() {
return this.first + ' ' + this.last;
};
function Employee(first, last, id) {
Employee.superclass.call(this, first, last);
this.id = id;
}
Class.extend(Employee, Person);
Employee.prototype.toString = function() {
return Employee.superproto.toString.call(this) + ': ' + this.id;
};
var peter = new Employee('Peter', 'Michaux', 3);
document.write(peter.toString()); // Peter Michaux: 3
// open the Person class and add a new method
Person.prototype.reverse_name = function() {
return this.last + ', ' + this.first;
};
document.write(peter.reverse_name()); // Michaux, Peter
And now we have all of this nice Ruby-type behavior with only the same simple eight lines of code that gave us the ability to simulate Ruby's "super". This is just another strength of the extend function.
Although Prototype.js itself doesn't need class-based inheritance, part of that libraries goal is to somewhat simulate Ruby in JavaScript. By included the extend function Prototype.js users could have Ruby-style classes enabled through a very simple JavaScript function.
Comments
Have something to write? Comment on this article.