Created
April 15, 2012 19:43
-
-
Save medikoo/2394476 to your computer and use it in GitHub Desktop.
JavaScript inheritance with *super*. Final solution (ES3 version)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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; | |
}; | |
}()); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
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.
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
That is way too long for a class lib.