Skip to content

Instantly share code, notes, and snippets.

@medikoo
Created April 15, 2012 19:43
Show Gist options
  • Save medikoo/2394476 to your computer and use it in GitHub Desktop.
Save medikoo/2394476 to your computer and use it in GitHub Desktop.
JavaScript inheritance with *super*. Final solution (ES3 version)
// Inspired partially by Isaac's inherits: https://github.com/isaacs/inherits
// No descriptors involved (needs to work same way on ES3 and ES5 engines)
// In older browsers needs to be run aside es5-shim: https://github.com/kriskowal/es5-shim
var extend = (function () {
'use strict';
var slice = Array.prototype.slice
, call = Function.prototype.call
, wantsSuper = RegExp.prototype.test.bind(/^\s*function\s*\(\s*_super\s*[,\)]/)
, prepare;
prepare = function (parent, child) {
var args;
if ((typeof child === 'function') && (typeof parent === 'function') && wantsSuper(child)) {
args = [call.bind(parent)];
return function () {
return child.apply(this, args.concat(slice.call(arguments)));
};
} else {
return child;
}
};
return function (parent, child, proto) {
if (typeof child !== 'function') {
if (child) {
proto = child;
}
child = function () {
return parent.apply(this, arguments);
};
} else {
child = prepare(parent, child);
}
proto = Object(proto);
child.prototype = Object.create(parent.prototype);
Object.keys(proto).forEach(function (name) {
this[name] = prepare(this[name], proto[name]);
}, child.prototype);
return child;
};
}());
var Animal = function (dateOfBirth) {
this.dateOfBirth = dateOfBirth;
};
Animal.prototype = {
say: function (what) {
console.log(what);
},
getAge: function () {
return Math.floor((Date.now() - this.dateOfBirth) /
(1000 * 60 * 60 * 24 * 365.25));
}
}
};
var Dog = extend(Animal, function (_super, dateOfBirth, breed) {
_super(this, dateOfBirth);
if (breed) {
this.breed = breed;
}
}, {
breed: 'mongrel',
say: function (_super) {
_super(this, 'woof woof');
}
});
var sparky = new Dog(new Date('2008-02-23'), 'Terrier');
sparky.name = 'Sparky';
console.log(sparky.getAge()); // 4
console.log(sparky.breed); // 'Terrier'
console.log(sparky.name); // 'Sparky'
console.log(sparky instanceof Animal); // true
console.log(sparky instanceof Dog); // true
@isaacs
Copy link

isaacs commented Apr 30, 2012

That is way too long for a class lib.

@medikoo
Copy link
Author

medikoo commented Apr 30, 2012

If someone needs handy 'super' it can't be much shorter.. and basically it's the only reason I would use that, otherwise plain JavaScript or some extend function like inherits works well enough.

@isaacs
Copy link

isaacs commented Apr 30, 2012

@medikoo
Copy link
Author

medikoo commented Apr 30, 2012

inherits doesn't help much with super verbosity:

// plain:
Animal.prototype.say.call(this, 'woof woof');

// inherits:
Dog.super.prototype.say.call(this. 'woof woof');

// extends:
_super(this, 'woof woof')

Maybe I didn't put myself clear. Main point of above is not just to have super handy but to have easy access to parent methods. Like we have in other languages, e.g. in PHP parent::say('woof') or in Java super.say("woof"). I don't see how inherits can help with that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment