I'm coming to Javascript from a background in Python and Smalltalk, and I appreciate the linage of Self and Lisp in the language. With ECMAScript5, I wanted to try my hand at prototypal OO without the new operator.
Constraints:
Here is my attempt at the implementation to meet the criteria:
function subclass(Class, Base) {
"use strict";
function create(self, args) {
if (!(self instanceof this))
self = Object.create(this.prototype);
var init = self.__init__;
return init ? init.apply(self, args) : self;
}
if (Base instanceof Function) Base = Base.prototype;
else if (Base===undefined) Base = Object.prototype;
Class.prototype = Object.create(Base);
Class.prototype.constructor = Class;
Class.create = create;
Class.define = function define(name, fn) { return Class.prototype[name] = fn; };
Class.define('__name__', Class.name);
return Class;
}
And it seems to work in a simple mockup:
function Family(){return Family.create(this, arguments)}
subclass(Family, Object);
Family.define('__init__', function __init__(n){this.name=n; return this;});
function Tribe(){return Tribe.create(this, arguments)}
subclass(Tribe, Family);
function Genus(){return Genus.create(this, arguments)}
subclass(Genus, Tribe);
function Species(){return Species.create(this, arguments)}
subclass(Species, Genus);
Using the class as a factory function:
var dog = Species('dog');
console.assert(dog instanceof Object);
console.assert(dog instanceof Family);
console.assert(dog instanceof Tribe);
console.assert(dog instanceof Genus);
console.assert(dog instanceof Species);
Or using the new operator:
var cat = new Species('cat');
console.assert(cat instanceof Object);
console.assert(cat instanceof Family);
console.assert(cat instanceof Tribe);
console.assert(cat instanceof Genus);
console.assert(cat instanceof Species);
console.assert(Object.getPrototypeOf(dog) === Object.getPrototypeOf(cat))
Have I overlooked needed features of prototypal OO in my implementation? Are there Javascript conventions or interactions I should make changes for? In summary, what are the "gotcha"s here, and are there any obvious improvements to be made?
I wanted to be DRYer with the constructor definitions, but I found that a function's name property is not writable, and that is what supports the WebKit Inspector's object names. I was able to construct an eval to accomplish what I wanted, but... yuck.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With