Not so easy functional programming in JavaScript

Introduction

JavaScript allows for operating on arrays in a functional way, e.g. using filter or map functions. As an argument for these functions we can pass lambda expression or function reference. Is there a difference between them? The answer is yes.

What’s the problem?

In our project we are building a mapping using String.fromCharCode function. To simplify the usage of this function looked similar to:

[66, 67, 68].map(v => String.fromCharCode(v))

When we run this code with node we received [ 'B', 'C', 'D' ], but when we decided to refactor it to use function reference the result was different:

> [66, 67, 68].map(String.fromCharCode)
[ 'B\u0000\u0000', 'C\u0001\u0000', 'D\u0002\u0000' ]

What happened?

To find the reason for this behavior, let’s first play with function String.fromCharCode alone:

> String.fromCharCode(66)
'B'
> String.fromCharCode([66, 67, 68])
'\u0000'
> String.fromCharCode(66, 67, 68)
'BCD'

String.fromCharCode deals with various types and numbers of arguments.

Now, let’s examine the function map:

> [66, 67, 68].map(v => v)
[ 66, 67, 68 ]
> [66, 67, 68].map((v, u) => [v, u])
[ [ 66, 0 ], [ 67, 1 ], [ 68, 2 ] ]
> [66, 67, 68].map((v, u, w) => [v, u, w])
[ [ 66, 0, [ 66, 67, 68 ] ],
  [ 67, 1, [ 66, 67, 68 ] ],
  [ 68, 2, [ 66, 67, 68 ] ] ]

map, like many other array functions, passes always three arguments to function. First is the current value, the second is the index of the current value and third is the whole array.

It means that passing String.fromCharCode to map function under the hood looks like this:

> [66, 67, 68].map((v, u, w) => String.fromCharCode(v, u, w))
[ 'B\u0000\u0000', 'C\u0001\u0000', 'D\u0002\u0000' ]

and it is equal to the initial example.

Conclusion

We must be careful when we want to use a function that can take more than one argument, but we want to pass only the value. We have to pass the function as a lambda expression:

> [66, 67, 68].map(v => String.fromCharCode(v))
[ 'B', 'C', 'D' ]

or create another function which ensures that only the first argument will be passed to desired function:

> const useOnlyValue = f => v => f(v);
undefined
> [66, 67, 68].map(useOnlyValue(String.fromCharCode))
[ 'B', 'C', 'D' ]
You May Also Like

Zabawy zespołowe: ćwiczenie głosu – RYBA!

Ćwiczenie ma za zadanie ośmielić osoby do mówienia głośno i wyraźnie. Ma też pomóc ustawić głos. Bardzo przydatne przy spotkaniach typu stand-up, gdzie "mruki" opowiadają pod nosem, co ostatnio robiły. Z mojego doświadczenia - działa!

Osoby biorące udział w ćwiczeniu stają w okręgu. Wybieramy sobie słówko do powtarzania. Proponowana jest ryba, ale może to być dowolne inne, proste w wymowie słowo.
Prowadzący ustala kierunek i jako pierwszy mówi szeptem ryba. Następnie, kolejne osoby powtarzają rybę, aż do donośnego"RYBA. Jeśli warunki pozwalają, można nawet krzyczeć, ale nie wrzeszczeć, bo wtedy wymowa jest niewyraźna. Po osiągnięciu maksymalnego (w pewnym sensie, ustalonego poziomu), zaczynamy ściszać głos, aż do szeptu. Naturalnie zabawę można powtórzyć dowolną ilość razy.

Jako szept warto przećwiczyć szept aktorski, czyli używanie szeptu, ale głośnego i wyraźnego, bez tembru głosu.

Mając jedno ustalone słowo, fajnie jest potem mobilizować kogoś kto mówi zbyt cicho wołając tylko "ryba!" i wtedy wszystko wiadomo.