Created
November 22, 2012 03:21
-
-
Save andrewplummer/4129295 to your computer and use it in GitHub Desktop.
Dead simple class inheritance
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
| (function() { | |
| var defineProperty = Object.defineProperty || function(obj, name, desc) { | |
| obj[name] = desc.value; | |
| }; | |
| var getOwnPropertyNames = Object.getOwnPropertyNames || function(obj) { | |
| var names = []; | |
| for(var key in obj) { | |
| if(!obj.hasOwnProperty(key)) continue; | |
| names.push(key); | |
| } | |
| return names; | |
| }; | |
| var defineMethod = function(obj, name, method, enumerable) { | |
| defineProperty(obj, name, { | |
| value: method, | |
| writable: true, | |
| configurable: true, | |
| enumerable: !!enumerable | |
| }); | |
| }; | |
| var mixin = function(source) { | |
| extend.call(this, source); | |
| extend.call(this.prototype, source.prototype); | |
| }; | |
| var extend = function(obj, enumerable) { | |
| var names = getOwnPropertyNames(obj), i = names.length, key; | |
| while(i--) { | |
| key = names[i]; | |
| if(key && !(key in this)) { | |
| defineMethod(this, key, obj[key], enumerable !== false); | |
| } | |
| } | |
| }; | |
| // "inherits" can be called in both the construtor of the inheriting class: | |
| // | |
| // var Foo = Class(function Foo() { | |
| // this.inherits(new Bar()); | |
| // }); | |
| // | |
| // ... or outside it: | |
| // | |
| // var Foo = Class(function Foo() {}); | |
| // Foo.inherits(Bar); | |
| // | |
| // The idea behind this is that often the constructor of the parent class needs | |
| // to be called, and calling it outside the context of the child class' constructor | |
| // often makes no sense. So, the first method makes sense when the parent's constructor | |
| // needs to be called, and the second makes sense when Foo simply inherits Bar's methods. | |
| // This is effectively identical to a mixin, and in fact this is not true prototypal | |
| // inheritance as the properties are being mixed in as non-enumerable methods instead of | |
| // actually setting the prototype object itself. This could be done through __proto__, | |
| // but it's dirtier and IE could not be supported. | |
| var inherits = function(parent) { | |
| var target = typeof this === 'function' ? this.prototype : this; | |
| if(typeof parent === 'function') { | |
| extend.call(target, parent.prototype, false); | |
| } else { | |
| extend.call(target, parent, false); | |
| extend.call(target, parent.constructor.prototype, false); | |
| } | |
| }; | |
| Class = function(constructor) { | |
| // Don't want to define methods on Function.prototype (yet), | |
| // so define them directly for now. | |
| defineMethod(constructor, 'mixin', mixin, true); | |
| defineMethod(constructor, 'extend', extend, true); | |
| defineMethod(constructor, 'inherits', inherits); | |
| defineMethod(constructor.prototype, 'extend', extend); | |
| defineMethod(constructor.prototype, 'inherits', inherits); | |
| return constructor; | |
| }; | |
| })(); |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Usage: