Last active
August 29, 2015 14:06
-
-
Save marlun78/cee41dd1cdaff01b3aba to your computer and use it in GitHub Desktop.
JavaScript prototypal inheritance
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
/** | |
* Class.js | |
* JavaScript prototypal inheritance | |
* Copyright (c) 2014 marlun78 | |
* MIT License, https://gist.github.com/marlun78/bd0800cf5e8053ba9f83 | |
* | |
* @example: | |
* function Person(name) { | |
* this.name = name; | |
* } | |
* | |
* Person.prototype.greet = function greet() { | |
* console.log('Hello, my name is', this.name); | |
* }; | |
* | |
* function Child(name) { | |
* this.super(name); | |
* } | |
* | |
* Child.extends(Person); // or Class.extends(Child, Person); | |
* | |
* var martin = new Person('Martin'); | |
* martin.greet(); // Hello, my name is Martin | |
* martin instanceof Person; // true | |
* martin instanceof Child; // false | |
* | |
* var ville = new Child('Ville'); | |
* ville.greet(); // Hello, my name is Ville | |
* ville instanceof Person; // true | |
* ville instanceof Child; // true | |
*/ | |
var Class = (function () { | |
'use strict'; | |
var Class = {}; | |
// Controversial, but I like it | |
Object.defineProperty(Function.prototype, 'extends', | |
new ValueDescriptor(extends_) | |
); | |
// ... or the hipster way | |
Object.defineProperty(Class, 'extends', | |
new ValueDescriptor( | |
function extendsFn(Constructor, Super) { | |
return extends_.call(Constructor, Super); | |
} | |
) | |
); | |
/** | |
* @this {Function} Constructor - The constructor function to extend from Super | |
* @param {Function|Object} Super - The constructor or object to extend from | |
* @return {Function} - Constructor | |
*/ | |
function extends_(Super) { | |
var isSuperFn, Constructor = this; | |
if (!isFunction(Constructor)) { | |
throw new TypeError('Constructor must be a function'); | |
} | |
isSuperFn = isFunction(Super); | |
if (!isSuperFn && !isObject(Super)) { | |
throw new TypeError('Super must be a function or an object'); | |
} | |
//Inherit from Super | |
Constructor.prototype = Object.create(isSuperFn ? Super.prototype : Super); | |
Object.defineProperties(Constructor.prototype, { | |
//Rebind the `constructor` property | |
constructor: new ValueDescriptor(Constructor), | |
//Create the `super` method | |
super: new ValueDescriptor(function super_() { | |
return isSuperFn ? Super.apply(this, arguments) : undefined; | |
}) | |
}); | |
return Constructor; | |
} | |
function isFunction(value) { | |
return typeof value === 'function'; | |
} | |
function isObject(value) { | |
return value && typeof value === 'object'; | |
} | |
/** | |
* @constructor | |
* @param {*} value | |
* @param {Boolean} [enumerable=false] | |
* @param {Boolean} [configurable=false] | |
* @param {Boolean} [writable=false] | |
* @return {ValueDescriptor} | |
*/ | |
function ValueDescriptor(value, enumerable, configurable, writable) { | |
this.value = value; | |
this.enumerable = !!enumerable; | |
this.configurable = !!configurable; | |
this.writable = !!writable; | |
} | |
return Class; | |
}()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment