Skip to content

Instantly share code, notes, and snippets.

@neeravp
Last active April 8, 2019 16:12
Show Gist options
  • Save neeravp/c00f1e66d2fb06673c00af0ddf1822e6 to your computer and use it in GitHub Desktop.
Save neeravp/c00f1e66d2fb06673c00af0ddf1822e6 to your computer and use it in GitHub Desktop.
Function to extend a class by mixing properties and methods from other objects or classes - composition not inheritance
function cmixin(target, ...sources) {
if(typeof target === 'function') {
sources.forEach(source => {
//When composing from an object
if(typeof source === 'object') {
Object.getOwnPropertyNames(source).forEach(prop => {
let descriptor = Object.getOwnPropertyDescriptor(source, prop);
Object.defineProperty(target, prop, descriptor);
});
Object.getOwnPropertySymbols(source).forEach(symbol => {
let descriptor = Object.getOwnPropertyDescriptor(source, symbol);
if(descriptor.enumerable) {
Object.defineProperty(target, symbol, descriptor);
}
});
}
//When composing from another class
else if(typeof source === 'function') {
//Get all instance properties and methods
Object.getOwnPropertyNames(source.prototype).forEach(prop => {
let descriptor = Object.getOwnPropertyDescriptor(source.prototype, prop);
//Do not copy constructor and readonly properties like name, length, prototype etc
if(descriptor.writable && prop !== 'constructor') {
//To allow overriding of instance methods remove this if
if(target.prototype[prop] === undefined) {
Object.defineProperty(target.prototype, prop, descriptor);
}
}
//To copy the instance properties defined in the source class constructor
//Don't think it is a good idea cause source constructor may have different set of args
// if(prop === 'constructor') {
// let instance = new source()
// Object.keys(instance).forEach(iprop => {
// if(target.prototype[iprop] === undefined){
// target.prototype[iprop] = instance[iprop]
// }
// });
// }
});
//Get all static properties and methods
Object.getOwnPropertyNames(source).forEach(prop => {
let descriptor = Object.getOwnPropertyDescriptor(source, prop);
//Do not copy the readonly properties like name, length, prototype
if(descriptor.writable) {
//To allow overriding of the static properties remove this if
if(target[prop] === undefined) {
Object.defineProperty(target, prop, descriptor);
}
}
});
}
});
}
return target;
}
@neeravp
Copy link
Author

neeravp commented Apr 7, 2019

Couldn't figure out a way to mixin getters and setters from one class to another.

Update:

Have factored a way to mixin getters and setters from other objects as well as classes to the target class.
Not sure if its the best approach though

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