How To Use The Spread Operator on a Function by@anirudh-eka

January 15th 2020 316 reads

You can’t officially do it, but you can write a function that does virtually the same thing. Let’s see how and maybe why you should.

But first, have you ever found yourself in this situation?

```
const result = f(x)
if(result === undefined) {
g(x)
}
```

You wanted to call a function with an input when another function returned undefined for that same input. The above works, but wouldn’t it be nice if we had something more generalized?

If we were using objects this could be nicely done with a spread operator.

`const combinedObj = {...gObj, ...fObj}`

😍 Doesn’t that look prettier? When I call

`combinedObj[x]`

it will return `fObj[x]`

unless `fObj`

is `undefined`

for `x`

. In that case, `gObj[x]`

would be returned. But what’s really nice is I can do it for any number of objects.`const combinedObj = {...gObj, ...fObj, ...hObj, ...iObj, ...jObj}`

So how could we define a function that could spread other functions similarly to how

`…`

spreads objects?Okay so

`spread`

should be able to take two functions, `f`

and `g`

```
const fObj = {a: 1, b: 2}
const gObj = {b: 3, c: 4}
const f = (x) => fObj[x]
const g = (x) => gObj[x]
spread(f, g)
```

and return a function that would first call

`g`

with an input and only if `g`

returns `undefined`

it will call `f`

.```
const combined = spread(f, g)
['a', 'b', 'c'].map(i => combined(i)) // => [1, 3, 4]
```

We can define the two function spread like this.

`const spread = (f, g) => g(x) !== undefined ? g(x) : f(x)`

If we want to spread more than two functions we can modify spread to take a list of functions.

```
const spread = fns =>
fns.reduce((a, f) => x => f(x) !== undefined ? f(x) : a(x))
spread([f, g, h, i, j])
```

Well, by itself it’s just a generification that follows a common javascript concept (‘spread’). If you understand how spread works with objects you will understand how spread works with functions. Takes a little less brain work than figuring out what the if statement that we started with was doing. It’s the same reason we use

`map`

and `reduce`

. There are many ways to achieve what `map`

and `reduce`

do without using them, but if we use them our code becomes much easier to follow at first glance.Additionally, spread allows us to wrap objects in functions for the benefit of lazy evaluation without sacrificing the ability to spread. In other words we can lazily spread as and when we need the output.

For example imagine we wanted a single value for a key in an object that was created by spreading two other objects.

```
const fObj = {a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8}
const gObj = {a: 100, c: 99, e: 88, g: 777}
const combined = {...fObj, ...gObj }
combined['d']
```

Then we would have to produce a fully new object combined with all new values even though we only needed the value for a single key,

`'d'`

. With our function spread, we can avoid creating a new object.```
const f = x => fObj[x]
const g = x => gObj[x]
const combined = spread([f, g])
combined('d')
```

Since what spread is actually building is a logical flow of ternaries and functions, when we ask for the value of a single key it executes the logic to get the value for only that key without worrying about getting the other values. Even this small example seems to show a performance gain. If we had to spread more times, we could save ourselves more intermediary objects and more time.

Finally since spread produces a function, we also get all the goodness of working with functions like function composition! Here is our spread definition again:

```
const spread = (...fns) =>
fns.reduce((a, f) => x => {
const v = f(x)
return v !== undefined ? v : a(x)
})
spread(f, g, h, i, j)
```

*There are a two slight differences between this definition and the one we saw earlier. 1. This one avoids the re-execution of *

`f(x)`

*undefined*

`spread(f, g)`

Try it out and let me know what you think! 😄