152 lines
4.3 KiB
Markdown
152 lines
4.3 KiB
Markdown
## My Best Attempts to Understand Function Currying in JavaScript
|
|
|
|
Recently while working on a React project, I saw an interesting use case where
|
|
a useRef({}) needed to be updated upon user interaction with a checkbox. Upon
|
|
consulting with ChatGPT, it spat out this as one small part of it's solution:
|
|
|
|
```
|
|
const toggleLinks = useRef({})
|
|
|
|
const saveToggleRef = id => elementRef => {
|
|
toggleLinks.current[id] = elementRef
|
|
}
|
|
```
|
|
|
|
When asking why the second arrow function was being done here, I was
|
|
reintroduced to the concept of function currying and how it worked. As a
|
|
beginner, I thought I knew what function currying was, but this proved the point
|
|
that (as always), when I think I know something, I don't. So let's dive in a bit
|
|
into what function currying is.
|
|
|
|
I decided to investigate more just what function currying is within the context of Vanilla JS, and came across [this stackoverflow query](https://stackoverflow.com/questions/51567907/how-does-a-reference-in-closure-and-currying-work-in-js).
|
|
|
|
The questioner simply posed their confusion at the following code:
|
|
|
|
```
|
|
function add(a) {
|
|
console.log("1");
|
|
var total = a;
|
|
console.log("2");
|
|
var _fn = function (b) {
|
|
console.log("3");
|
|
total += b;
|
|
console.log("4");
|
|
return _fn;
|
|
};
|
|
console.log("5");
|
|
_fn.toString = _fn.valueOf = function () {
|
|
console.log("6");
|
|
return total;
|
|
};
|
|
console.log("7");
|
|
console.log("_fn: " + _fn);
|
|
return _fn;
|
|
}
|
|
```
|
|
|
|
Which upon running add(1)(2) outputs:
|
|
|
|
```
|
|
1
|
|
2
|
|
5
|
|
7
|
|
6
|
|
_fn: 1
|
|
3
|
|
4
|
|
6
|
|
ƒ 3
|
|
```
|
|
|
|
The questioner posits that technically the inner function \_fn, should create an
|
|
infinite loop due to its reference to itself, but as the person who has the
|
|
highest voted answer points out, \_fn is never called, but rather is simply
|
|
returned out of itself, and then also returned from the original function after
|
|
it is given an additional property, toString. If \_fn were called/invoked within itself,
|
|
then yes this creates an infinite loop, but this never happens.
|
|
|
|
This points to an interesting aspect of JavaScript which is that everything is
|
|
an Object. Consider the definition of \_fn:
|
|
|
|
```
|
|
var _fn = function (b) {
|
|
console.log("3");
|
|
total += b;
|
|
console.log("4");
|
|
return _fn;
|
|
};
|
|
```
|
|
|
|
Consider this as being like an Object with a variable b that is associated with
|
|
it, and assigned to the [args] array (keep in mind, beginner here, terms could
|
|
be incorrect). Taking away the console logs, let's look at the total (initially assigned
|
|
to our first outer functions first argument, a), which takes its original value
|
|
and adds it to our inner functions first argument, to b. It then RETURNS ITSELF.
|
|
Given what we know thus far, it means that the value of total should now be 3
|
|
when \_fn is called, which is done when the original function is called in its
|
|
invocation add(1)(2). The second call (2), is what invokes \_fn as far as I know.
|
|
|
|
Notice, however, that we have a third function curried up to \_fn:
|
|
|
|
```
|
|
_fn.toString = _fn.valueOf = function () {
|
|
console.log("6");
|
|
return total;
|
|
};
|
|
```
|
|
|
|
We're now overwriting Object primitives, \_fn.toString is reassigned to
|
|
\_fn.valueOf (in this case \_fn), which is then reassigned to returning the total.
|
|
|
|
The print values are there to show the order of operations, take a look again
|
|
and notice that they are not in order:
|
|
|
|
```
|
|
1
|
|
2
|
|
5
|
|
7
|
|
6
|
|
_fn: 1
|
|
3
|
|
4
|
|
6
|
|
ƒ 3
|
|
```
|
|
|
|
An interesting piece of confusing magic is happening here due to the way the JS
|
|
runtime runs synchronously. The reassigning of \_fn.toString to the value
|
|
returned of \_fn.valueOf, which itself is reassigned to simply return the total
|
|
returns 1, but this is our original value in add(1)(2)??? This is because this
|
|
statement:
|
|
|
|
```
|
|
return total;
|
|
```
|
|
|
|
Within the \_fn.toString... function has yet to read the adjusted:
|
|
|
|
```
|
|
total += b;
|
|
```
|
|
|
|
Within the original declaration of \_fn. However, then the last line finally
|
|
returns the \_fn function, which has a valueOf within it. At this point the
|
|
entire runtime of the JavaScript function is complete and total HAS BEEN
|
|
reassigned to:
|
|
|
|
```
|
|
total += b;
|
|
```
|
|
|
|
And thusly add(1)(2) will indeed return 3, producing our final line in the
|
|
output:
|
|
|
|
```
|
|
ƒ 3
|
|
```
|
|
|
|
The cursive style 'ƒ' character indicates the return of a function instead of a
|
|
value, but it also shows its return value (as it returns itself I suppose). I'll
|
|
admit this aspect of the output still confuses me, but we'll get there...
|