Last active
October 12, 2015 14:07
-
-
Save amatiasq/4038135 to your computer and use it in GitHub Desktop.
Simple base class with this.base() to call parent mehtod
This file contains 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
/** | |
* Provides: | |
* Function extend(Function parent, Object config); | |
* | |
* It extends constructors with it's methods | |
* Also provides to every method who overwrites another one | |
* with a this.base() method to invoke overwrote method. | |
* | |
* Created constructor has methods | |
* .extend(Object config) | |
* and | |
* .inject(Object config) | |
*/ | |
(function(root) { | |
"use strict"; | |
var has = Object.prototype.hasOwnProperty; | |
/** | |
* Oh come on! You don't need me to explain this. | |
*/ | |
function each(map, callback, scope) { | |
for (var i in map) | |
if (has.call(map, i)) | |
callback.call(scope, map[i], i, map); | |
} | |
/** | |
* Wraps a function to garantee it has this.base() in order to cal overwrote method | |
*/ | |
function wrap(funct, base) { | |
return function() { | |
var a = this.base; this.base = base; | |
// If you are here and don't know what to do, debug into the next line | |
var result = funct.apply(this, arguments); | |
return (this.base = a), result; | |
}; | |
} | |
/** | |
* Prototypes a object and injects given configuration. | |
* Does not respect child, it can return the same object or a new one depending on browser. | |
*/ | |
var proto = ({}).__proto__ ? | |
function(child, parent) { return (child.__proto__ = parent), child } : | |
function(config, parent) { | |
intermediate.prototype = parent; | |
var child = new intermediate(); | |
each(config, function(val, i) { child[i] = val }); | |
return child; | |
}; | |
/** | |
* Adds every item in config to obj | |
* If it's a function it will wrap it in order to have this.base(); | |
* | |
* @param obj <Object> The object where the properties will be injected. | |
* @param config <JSON> The object with methdos to inject. | |
*/ | |
function inject(obj, config) { | |
each(config, function(value, prop) { | |
if (typeof value === 'function' && obj[prop]) | |
obj[prop] = wrap(value, obj[prop]); | |
else | |
obj[prop] = value; | |
}); | |
} | |
/// Dummy, just for prototype | |
function intermediate() { } | |
/** | |
* Creates a new function who's prototype property extend <Parent>'s prototype property. | |
* | |
* @param Parent <Function> The constructor of the type to extend. | |
* @param config <JSON> Object with methods to add to the new type. | |
* @returns <Function> The constructor of the new type. | |
*/ | |
function extend(Parent, config) { | |
config = config || {}; | |
// We create the constructor | |
var ctor = has.call(config, 'constructor') && | |
typeof config.constructor === 'function' ? | |
wrap(config.constructor, Parent) : | |
function() { Parent.apply(this, arguments); }; | |
// Add basic static methods | |
ctor.extend = function(desc) { return extend(this, desc) }; | |
ctor.inject = function(desc) { return inject(this.prototype, desc) }; | |
// Copy parent's statics | |
inject(ctor, Parent); | |
// Extend parent prototype | |
intermediate.prototype = Parent.prototype | |
ctor.prototype = new intermediate; | |
// Apply new methods | |
ctor.inject(config); | |
// Fix constructor | |
ctor.prototype.constructor = ctor; | |
return ctor; | |
} | |
if (typeof module !== 'undefined' && module.exports) | |
module.exports = extend; | |
else if (typeof define !== 'undefined' && define.amd) | |
define(function() { return extend }); | |
else | |
root.extend = extend; | |
})(this); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment