Composition > Inheritance
Unless you’ve been coding under a rock, you know about the ES6/ES201* class syntax, which offers a constructor function and demands that you include super() if you wanna use this anywhere in your function. This is great syntactically if you’re used to classical OOP languages, but I think it’s masking the most powerful and flexible aspect of JS: prototypes and object concatenation. Besides, class/constructor/super are just playing a prototypical shell game under the hood.
There are several ways to use a functional approach to creating new objects and patterns, one of which is called the Factory Function, and I really like it. I like it so much in fact that I cooked up my own implementation and called it Unifactory. I named it that because it takes an arbitrary number of arguments, analyzes their type and returns them as properties of an object.
function Factory () { const args = Array.from(arguments), obj = {}; obj.__proto__ = defaultProps; args.forEach(function(arg) { if (typeof(arg) === 'function') { obj[arg.name] = arg } else if (typeof(arg) === 'object') { for (let key in arg) { obj[key] = arg[key] } } else { obj[arg] = arg } }); return obj; } // Assign some default properties. ****/ const defaultProps = { defaultPhrase: function (phrase) { console.log(phrase); } }; //*************************************/ // Create an observer pattern. ************/ const customEvent = Factory({ events: {}, add: function (event, callback) { this.events[event] = callback; }, dispatch: function (event, args) { this.events[event](args); } }); customEvent.add('walk', function (dest) { console.log('I am walking to ' + dest); }); customEvent.dispatch('walk', 'the store.'); //*****************************************/ // Create some people with properties. ***************************/ let michael = Factory({name:'Michael'}, function speak (phrase) { console.log('I am ' + michael.name + ' and ' + phrase); }); let zick = Factory({name:'Zick'}, function say (phrase, action) { console.log('I am ' + zick.name + ', ' + 'and I '+ phrase + ' ' + action + '.'); }); zick = Object.assign(zick, { retort: function (phrase) { console.log(phrase); } }); michael.speak('I\'m a developer.'); zick.say('might be', 'surfing'); zick.retort('I\'m probably enineering something now.'); michael.defaultPhrase('This is the default phrase.'); //****************************************************************/