I am playing with classical inheritance in Javascript (in Chrome) following the example of Crockford. I like the parasitic interface but am looking for a bit cleaner way to encapsulate inheritance.
There are a couple additional requirements I am trying to meet:
- I'd like to be able to override methods of the parent class with methods in the child class that can call the parent method
- I don't want to have to re-declare properties of the parent class in the child class.
This is my parent class Parasite
with an extend
method that tries to encapsulate inheritance and take advantage of Object.defineProperty
:
function Parasite(host) {
var self = {};
self.host = host;
self.swollen = false;
self.init = function() {
console.debug('Parasite.init');
return self;
};
self.suck = function() {
console.log("I'm a parasite who sucks on " + self.host);
self.swollen = true;
return self;
};
self.extend = function(child) {
for(var prop in self) {
if (prop == 'extend') { // skip extend
console.debug('skip extend');
continue;
}
var is_extended = child.hasOwnProperty(prop);
var is_accessor = typeof self[prop] != "function";
// inherit prop
if (! is_extended) {
child[prop] = self[prop];
console.debug('prop', prop, 'inherited by child');
}
// default: override
else {
console.debug('prop', prop, 'overridden by child');
}
// For accessors, parent should reference child. This tries to
// synchronize them on the child's accesor.
if (is_accessor) {
var accessor = prop.toString();
console.warn('define accessor for', accessor, ':', child[accessor]);
Object.defineProperty(self, accessor, {
get: function() {
var val = child[accessor];
console.debug('getting', accessor, val, 'from', child, 'for', self);
return val;
},
set: function(val) {
console.debug('setting', accessor, val, 'from', child, 'for', self);
child[accessor] = val;
},
enumerable: true,
configurable: true
});
};
}
child.parent = self;
return child;
};
self = self.init();
return self;
}
This is my child class, Tick
:
function Tick(host) {
var self = {};
self.suck = function() {
self.parent.suck.call();
self.engorge();
};
self.engorge = function() {
console.log("And now I'm engorged with blood.");
};
self.init = function() {
var parent = new Parasite(host);
self = parent.extend(self);
return self;
};
self = self.init();
return self;
}
You can find my latest fiddle here (warning: infinitely recurses in Firefox, but not in Chrome):
The console output illustrates where the accessor issues are occurring.