DEV Community

loading...
Cover image for 3 useful JavaScript Generic Function Currying methods

3 useful JavaScript Generic Function Currying methods

Jakub Jabłoński
Yet another Web Developer
・2 min read

Intro

There are some cases when you deal with multiple functions either when they are completely separate or depend on each other. I'm sure you have stumbled upon the problem that could use some helpers. I will present some methods I found useful for dealing with that problem.

Disclaimer

I'm not an expert by any means, this blog is just result of me learning and trying to understand some concepts deeper while sharing it. Maybe someone will find it interesting. Any feedback appreciated.

runAll

Let's start from something easy to read. One of the simplest yet powerful examples is runAll function you could implement as following:

const runAll = (...fns) => fns.forEach(func => func?.())
Enter fullscreen mode Exit fullscreen mode

It runs all functions one by one.

If you don't know what this (func?.()) does it just runs function only when it's defined

runAll example

const handleRefresh = runAll(closeModal, clearSearch, clearFilter, clearSort)
handleRefresh()
Enter fullscreen mode Exit fullscreen mode

It's just a simple and elegant solution when you want to run multiple void functions. I personally think that it helps to keep your code clean and DRY.

chain

If your functions depends on each other you might want to use function chaining similarly to:

const chain = (...fns) => (...args) => fns.reduce((arg, func) => func(arg), args)
Enter fullscreen mode Exit fullscreen mode

It runs functions one by one passing previous function result as the parameter.

This one-line function is incredibly powerful and gives you lots of possibilities.

If you want to have more math alike nesting you use reduceRight so if you combine a,b,c it's interpreted as a(b(c)) instead of c(b(a)).

chain example

const increment = (x) => +x + 1
const decrement = (x) => +x - 1
const square = x => x * x

const chained = chain(increment, square, decrement)
console.log(chained(2)); // 8
Enter fullscreen mode Exit fullscreen mode

Value passed as an argument is first incremented then squared and finally decremented. Kind of silly example, but you get the idea.

combineResults

Sometimes you only care about combining the results of function. Usually it's only two functions but if you have to write it anyway why not make it generic?

const combine = (...fns) => (...args) => fns.reduce((results, func) => ({ ...results, ...func?.(...args) }), {})
Enter fullscreen mode Exit fullscreen mode

It's little bit harder to read but all it does is running all functions with the same parameters and then combining the results.

combine example

const funcA = (prop) => ({
  common: 'A',
  propA: 'A ' + prop
})

const funcB = (prop) => ({
  common: 'B',
  propB: 'B ' + prop
})

const funcC = (prop) => ({
  common: 'C',
  propC: 'C ' + prop
})


const combined = combine(funcA, funcB, funcC)

console.log(combined('demo')) // { common: 'C', propA: 'A demo', propB: 'B demo', propC: 'C demo' } 
Enter fullscreen mode Exit fullscreen mode

As you can see unique properties of the objects are all present in the result, but the common that was shared between all functions got overridden by funcC.

It's the same as just calling all functions and doing {...resA, ...resB, ...redC}

That's basically it

That's all I came up with when it comes to functions one-liners. Have you ever used something similar in a project?

Discussion (0)