I come to Javascript from the background in Python and Smalltalk, and I appreciate the Self and Lisp line in the language. With ECMAScript5, I wanted to try my hand at prototype OO without a new operator.
Limitations:
- optional new operator for creating classes Prototype chain
- must be correct for instance
- named constructors to support WebInspector debugging
- alloc (). Init () creation sequence such as Objective-C and Python
Here is my implementation attempt to fulfill 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 this looks like a simple layout:
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 really forgotten about the necessary capabilities of prototype OO in my implementation? Are there any Javascript conventions or interactions for which I have to make changes? So what are the “gains” here, and are there any obvious improvements that need to be made?
I wanted to be DRYer with constructor definitions, but I found that the function name property is not writable, and that is what supports the names of the WebKit Inspector objects. I was able to build eval to accomplish what I wanted, but ... yuck.