const objs = [ { a: 'a', b: 'ab' }, { b: 'b' }, { c: 'c', b: 'cb' }, ]; // aggregation const collection = (a, e) => a.concat([e]); const a = objs.reduce(collection, []); console.log( 'collection aggregation', a, a[1].b, a[2].c, `Enumerable keys: ${Object.keys(a)}` ); // linked list aggreagation using pairs: const pair = (a, b) => [b, a]; const l = objs.reduceRight(pair, []); console.log( 'linked list aggregation', l, `enumerable keys: ${Object.keys(l)}` ); console.log(l[1]) // concatenation const concatenate = (a, o) => ({ ...a, ...o }); const c = objs.reduce(concatenate, {}); console.log( 'concatenation', c, `enumerable keys: ${Object.keys(c)}` ); // delegation const delegate = (a, b) => Object.assign(Object.create(a), b); const d = objs.reduceRight(delegate, {}); console.log( 'delegation', d, `enumerable keys: ${Object.keys(d)}` ); console.log(d.b, d.c); // Factory functions // for one: literal objects const user = { name: 'Pablo', lastName: 'Fernandez', setName (name) { this.name = name; return this; } }; console.log(user.setName('Pedro').name); // for many const createUser = ({ name = "Anonymous", age = 0 } = {}) => ({ name, age, setName (name) { this.name = name; return name; } }); console.log(createUser({ name: 'Pablo', age: 27 })) console.log(createUser({ name: 'Pedro', age: 37 })) // Factory functions for mixin composition const withConstructor = constructor => o => ({ __proto__: { constructor }, ...o }); const pipe = (...fns) => x => fns.reduce((y, f) => f(y), x); const withInfo = ({ name }) => o => { return { getName () { return name; } } }; const createO = ({ name = 'Pablo' }) => pipe( withInfo({ name }), withConstructor(createO) )({}); const t = createO({}); console.log(t.getName()); console.log(t.constructor === createO) // Functional mixins const chocolate = { hasChocolate: () => true }; const caramel = { hasCaramel: () => true }; const mandms = { hasMandms: () => true }; const iceCream = Object.assign({}, chocolate, caramel, mandms); // const iceCreamte = { ...chocolate, ...caramel, ...mandms } console.log(iceCream.hasCaramel()); console.log(iceCream.hasChocolate()); console.log(iceCream.hasMandms()); // another example const running = o => { let isRunning = false; return Object.assign({}, o, { run () { isRunning = true; return this; }, isRunning: () => isRunning, stop () { isRunning = false; return this; } }); }; const rabbit = running({}); console.log(rabbit.isRunning()) console.log(rabbit.run().isRunning()) const grunting = sound => o => Object.assign({}, o, { grunt: () => sound }); const duck = grunting('Quack')({}); console.log(duck.grunt()); // composing weird const createDuck = () => grunting('Quack')(running({})); const duck2 = createDuck(); console.log(duck2.grunt()); console.log(duck2.run().isRunning()); // composing with pipe const createDog = () => pipe( running, grunting('Wag'), )({}); const dog = createDog(); console.log(dog.grunt()); console.log(dog.run().isRunning()); // Working with prototypes const proto = { test: { name: 'buy', }, position: [0, 0], name: 'Test' }; // const createP = options => Object.assign(Object.create(proto), options); const createP = options => ({ ...proto, test: ...(proto.test), ...options }); const p = createP(); const j = createP(); console.log(p.position); p.test.name = 'e'; console.log(j.test); console.log(proto);