# JavaScript kitchen secrets: spices

Original author: Riccardo Odone
• Transfer
Take a look at the following code snippets that solve the same problem, and think about which one you like best.
 Here is the first: Here is the second: ``````[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] .filter(int => isEven(int)) .filter(int => isBiggerThan(3, int)) .map(int => int + 1) .map(int => toChar(int)) .filter(char => !isVowel(char)) .join('') // 'fhjl'`````` ``````[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] .filter(isEven) .filter(isBiggerThan(3)) .map(plus(1)) .map(toChar) .filter(not(isVowel)) .join('') // 'fhjl'``````
“I bet that the second version has a much better readability than the first,” says the author of the material, the translation of which we are publishing today. According to him, it’s all about the arguments of the methods `filter()`and `map()`. Today we will talk about how to recycle code like the first example, so that it looks like the code from the second. The author of the article promises that after you understand how it works, you will relate to your programs in a new way and will not be able to ignore what used to seem quite normal and not requiring improvement.

## Simple function

Consider a simple function `sum()`that adds the numbers passed to it:

``````const sum = (a, b) => a + b
sum(1, 2)
// 3``````

Rewrite it, giving the new function a name `csum()`:

``````const csum = a => b => a + b
csum(1)(2)
// 3``````

It works its new version in the same way as the original one, the only difference is how this new function is called. Namely, the function `sum()`takes two parameters at once, and `csum()`takes the same parameters one by one. In fact, when accessing, `csum()`two functions are called. In particular, consider the situation when they `csum()`call, passing it the number 1 and nothing else:

``````csum(1)
// b => 1 + b``````

Such a call `csum()`leads to the fact that it returns a function that can take the second numeric argument passed `csum()`in its usual call, and returns the result of adding one to this argument. Let's call this function `plusOne()`:

``````const plusOne = csum(1)
plusOne(2)
// 3``````

## Work with arrays

In JavaScript, you can work with arrays using a variety of special methods. Let's say the method is `map()`used to apply the function passed to it to each element of the array.

For example, in order to increase by 1 each element of an integer array (more precisely, to form a new array containing elements of the original, increased by 1), you can use the following construction:

``````[1, 2, 3].map(x => x + 1)
// [2, 3, 4]``````

In other words, what is happening can be described as follows: the function `x => x + 1`takes an integer and returns the number that follows it in the series of integers. If we use the above function `plusOne()`, this example can be rewritten as follows:

``````[1, 2, 3].map(x => plusOne(x))
// [2, 3, 4]``````

There is a moment to slow down and think about what is happening. If this is done, then it can be noted that in the considered case the constructions `x => plusOne(x)`and `plusOne`(note that in this situation there are no brackets after the function name) are equivalent. In order to better deal with this, consider the function `otherPlusOne()`:

``````const otherPlusOne = x => plusOne(x)
otherPlusOne(1)
// 2``````

The result of this function will be the same as that obtained by a simple call already known to us `plusOne()`:

``````plusOne(1)
// 2``````

For the same reason, we can talk about the equivalence of the following two constructions. Here is the first we have already seen:

``````[1, 2, 3].map(x => plusOne(x))
// [2, 3, 4]``````

Here is the second:

``````[1, 2, 3].map(plusOne)
// [2, 3, 4]``````

In addition, recall how the function was created `plusOne()`:

``const plusOne = csum(1)``

This allows us to rewrite our design with the `map()`following:

``````[1, 2, 3].map(csum(1))
// [2, 3, 4]``````

Let's create now using the same method, function `isBiggerThan()`. If you want, try to do it yourself, and then continue reading. This will eliminate the use of unnecessary constructions when using the method `filter()`. First, we give the code to this form:

``````const isBiggerThan = (threshold, int) => int > threshold
[1, 2, 3, 4].filter(int => isBiggerThan(3, int))``````

Then, getting rid of all the excess, we get the code that you have already seen at the very beginning of this material:

``````[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
.filter(isEven)
.filter(isBiggerThan(3))
.map(plus(1))
.map(toChar)
.filter(not(isVowel))
.join('')
// 'fhjl'``````

We now consider two simple rules that allow you to write code in the style considered here.

## Rule number 1

The following two constructions are equivalent:

``````[…].map(x => fnc(x))
[…].map(fnc)``````

## Rule number 2

Callback can always be rewritten to reduce the number of arguments used when it is called:

``````const fnc = (x, y, z) => …
[…].map(x => fnc(x, y, z))
const fnc = (y, z) => x => …
[…].map(fnc(y, z))``````

If you wrote the function yourself `isBiggerThan()`, then you probably already resorted to a similar transformation. Suppose we need to pass through the filter numbers that are greater than 3. This can be done as follows:

``````const isBiggerThan = (threshold, int) => int > threshold
[…].filter(int => isBiggerThan(3, int))``````

Now we will rewrite the function `isBiggerThan()`so that it could be used in the method `filter()`and not resort to the construction `int=>`:

``````const isBiggerThan = threshold => int => int > threshold
[…].map(isBiggerThan(3))``````

## Exercise

Suppose we have the following code snippet:

``````const keepGreatestChar =
(char1, char2) => char1 > char2 ? char1 : char2
keepGreatestChar('b', 'f')
//'f'// так как 'f' идёт после 'b'``````

Now, based on the function `keepGreatestChar()`, create a function `keepGreatestCharBetweenBAnd()`. We need that, calling it, it would be possible to pass to it only one argument, while it will compare the character passed to it with the character `b`. This function may look like this:

``````const keepGreatestChar =
(char1, char2) => char1 > char2 ? char1 : char2
const keepGreatestCharBetweenBAnd = char =>
keepGreatestChar('b', char)
keepGreatestCharBetweenBAnd('a')
// 'b'// так как 'b' идёт после 'a'``````

Now write a function `greatestCharInArray()`that, using the function `keepGreatestChar()`in an array method, `reduce()`allows you to search for the “largest” character and does not need arguments. Let's start with this code:

``````const keepGreatestChar =
(char1, char2) => char1 > char2 ? char1 : char2
const greatestCharInArray =
array => array.reduce((acc, char) => acc > char ? acc : char, 'a')
greatestCharInArray(['a', 'b', 'c', 'd'])
// 'd'``````

To solve this problem, implement a function `creduce()`that can be used in a function `greatestCharInArray()`, which will allow, in the practical application of this function, not to transfer to it anything other than an array in which you need to find the symbol with the largest code.

The function `creduce()`must be sufficiently universal so that it can be used to solve any problem in which you want to use the capabilities of the standard array method `reduce()`. In other words, the function must accept a callback, an initial value, and an array to work with. As a result, you should have a function with which the following code fragment will work:

``````const greatestCharInArray = creduce(keepGreatestChar, 'a')
greatestCharInArray(['a', 'b', 'c', 'd'])
// 'd'``````

## Results

Perhaps now you have a question about why the methods, processed in accordance with the method presented here, have names starting with a symbol `c`. A symbol `c`is an abbreviation for curried — and we’ve talked about how curried functions help improve readability of the code. It should be noted that we did not strive here for strict adherence to the principles of functional programming, but we believe that the practical application of what was discussed here allows us to improve the code. If the topic of currying in JavaScript is interesting to you, it is recommended to read chapter 4 of thisbooks on functional programming, and, in general, since you have reached this place - read the whole book. In addition, if you are new to functional programming, pay attention to this material for beginners.

Dear readers! Do you use currying functions in JavaScript development? 