4m1r 4m1r - 1 month ago 20
Javascript Question

Properly merge two functions in JavaScript

I've searched around SO a bit and can't find any solutions that seem to do what I'm trying to do. I have two objects with the some of the same properties.

this.defaultEvents = {
[FOCUS]: (e) => {
this.focusHandler(e);
},
[BLUR]: (e) => e
};

this.otherEvents = {
[FOCUS]: (e) => {
this.otherFocusHandler(e);
}
}


I want to be able to merge these properties, so that somehow I get something like this...

this.mergedEvents = {
[FOCUS]: (e) => {
this.focusHandler(e);
this.otherFocusHandler(e);
},
[BLUR]: (e) => e
};


So that I can invoke
(e) => this.mergedEvents[FOCUS](e)
and have both focus handlers be called with the same arguments.

This question seems to be the closest thing to what I'm trying to do. I guess a call to each function should work?

Extend a function - merge two functions?

This temporary solution seems to work, but I guess I should be using call or apply? I'm not too familiar with either of them.

const merged = {};

for(let key in defaultEvents) {

if ( otherEvents.hasOwnProperty( key ) && typeof otherEvents[key] === 'function') {
merged[key] = function(e) {
defaultEvents[key](e);
otherEvents[key](e);
}
}

}

merged[FOCUS]('test');


here's a code pen too

Answer

You can iterate keys of object and create composed functions for each key, e.g.:

function merge(...events) {
  const all = events
    .map(e => Object.keys(e)) // map keys
    .reduce((a, b) => [...a, ...b], []); // flatten
  const unique = [...new Set(all)]; // remove duplicates
  return unique.reduce((r, key) => {
    const handlers = events
      .filter(e => e[key]) // filter out not relevant handlers
      .map(e => e[key]); // extract concrete handler
    r[key] = e => handlers.map(h => h(e)); // compose functions with map
    return r;
  }, {});
}