Welcome back π, my gorgeous friend on the internet.
Today we will be learning the almighty currying in JavaScript, but before we continue, I assume you are here because you have written your first line of code in JavaScript and already have basic knowledge of what functions are in JavaScript.
Announcement break
Happy to announce that I have joined the freecodecamp Author Community as one of their technical writers, thanks to my readers, the Hashnode team for providing an enabling environment to get better at writing and to all other writers on Hashnode for their amazing energy and feedbacks.
Get ready to read my first article on freecodecamp very soon.
Welcome back
Because I want you to follow along well and learn from this article, I have gotten 2 reader-friendly articles on JavaScript functions from the Hashnode community and I will advise you to check them out and then come back to read more about the ABC of JavaScript currying.
ARTICLES ON JAVASCRIPT FUNCTION
Now that we are on the same page, let's do this by firstly looking into what JavaScript Currying is actually all about and why you should care about it.
Also at the end of this article, you will;
Have a basic understanding of how JavaScript currying works
Complete a simple use case application of JavaScript currying, and
Finally you won't forget what Javascript currying is π
What is Currying?
Currying is a process in functional programming in which we can transform a function with multiple arguments into a sequence of nesting functions. It returns a new function that expects the next argument inline.
Don't be confused yet, I have broken the above definition into two parts below which we are going to pick one after the other.
In this article, we will term currying as
A function returning a new function and
A process of converting a function with multiple arguments into a sequence of nesting functions.
1. A function returning a new function
It returns a new function that expects the next argument inline.
(Source: Definition above)
We should know by now that a function is a block of codes that are used to perform an action, which returns a value.
Example 1
// Function that returns a blog url
function getBlogUrl (){
// Blog url
const blogUrl = "https://www.unclebigbay.com";
// getBlogUrl return statement to the caller
return blogUrl;
};
// The caller display the value returned from getBlogUrl and it's data type to the screen
document.write(getBlogUrl() + " - " + typeof(getBlogUrl()))
Output
In the above example, we have a function named getBlogUrl
whose job is to return a string value of blogUrl
as a response to it caller, the caller in this example is the document.write(getBlogUrl())
.
This means that whenever we call the getBlogUrl
function the return response we get from the function will always be the value of blogUrl
which is a string
data type.
Point: the function
getBlogUrl
is returning astring
value data type
Example 2
Let say we have the function below
// Function that adds two numbers together
function add2Numbers (number1, number2){
// Add the two given numbers and store in answer
const answer = number1 + number2;
// Return the answer to the caller
return answer;
};
// The caller
document.write(add2Numbers(1, 2) + " - " + typeof(add2Numbers(1, 2)))
Output
In this example 2, we have a function add2Numbers
that takes in two parameters number1
and number2
, and then return the sum of the two arguments passed from the caller.
The main thing to observe from this function is the data type of the returned value from the add2Numbers
function which is the Number
type.
Point: the function
add2Numbers
is returning aNumber
value data type
To this point, we have seen that a function can return a String
and Number
data type as its value when been invoked, now let's see how we can make a function return a function as its value.
Note: function call === invoke function
Example 3
Let's take a look at this example 3 below
// A function that returns a function
function xFunction(){
// Function being returned to the caller
return function(){
// We will do something here later
};
};
// The caller
document.write(xFunction() + " - " + typeof(xFunction()));
Output
The xFunction
returns the inner function
as a plain text because the inner function is not invoked by the caller, so the return statement of the xFunction
treats the inner function as a plain text but its data type is a function as we can see in the output above (JavaScript is weird).
So how do we call the inner function? π€
But wait, in the real application of the currying function, you won't be calling the curried function (xFunction
in this case) without calling the inner function, so don't be worried about the plain text function been returned.
Note: inner function === nested function
To draw the point that we are actually returning a function, let's update Example 4 with the code below
// add () to the xFuntion()
document.write(xFunction()() + " - " + typeof(xFunction()()));
Output
Now we have a function returning a function, thanks for reading, the end!!!
No, I was just kidding π, we are still together on this, I know by now you are probably wondering "hey unclebigbay why did we have undefined
as the returned value and data type on the screen?π€·ββοΈ
But did you notice we did not return any value from the inner function? πββοΈ
return function(){
// We will do something here later
};
Remember now? The undefined
on the screen is a value we get because the inner function does not return any value.
This is 100% normal because the default returned value of a function is
undefined
and the datatype ofundefined
is alsoundefined
console.log(typeof undefined) // undefined
The extra bracket ()
we added to the xFunction
signifies that the xFunction
has a function within it which we want to execute.
Now let's return an actual value from the inner function
Example 4
function xFunction(){
return function(){
// Return the sum of 1 and 1 to the caller
return 1 + 1
};
};
// The caller
document.write(xFunction()() + " - " + typeof(xFunction()()));
Output
The inner function is now returning a value of
Number
data type
Why does this make sense?
First-class citizens can be treated like every other thing like variable values
in JavaScript, just like a citizen of a country.
Objects are first-class citizens in JavaScript and
Functions are Objects
First-class citizenship simply means βbeing able to do what everyone else can do.β (Source: Developer Intelligence )
This implies that, if you can return a
String
and a Number
data type as a return value in a function, then a function is qualified to be a returned value also.
This explains why an arrow function is possible in JavaScript, assigning a function to a variable.
Wow, we just covered the definition of currying as a function that returns a new function, let us proceed to complete the second definition.
2. A process of converting a function with multiple arguments into a sequence of nesting functions.
This is a continuation of where we stopped and what we have been doing in the first definition, but we will dive more deeply into currying itself in this second definition.
Now let us make the returned value from Example 4 dynamic, instead of hardcoding the value 1 + 1
, let's make the caller determine what two numbers to add up.
Example 5
Let's update Example 4 with the code below
function xFunction(number1){
return function(number2){
// Return the sum of number1 and number2 to the caller
return number1 + number2
};
};
// The caller passed 1 to xFunction and 3 to the inner function
document.write(xFunction(1)(3) + " - " + typeof(xFunction()()));
Output
The above function can be written as
// Regular function
function xFunction(number1, number2){
// Return the sum of number1 and number2 to the caller
return number1 + number2
};
// The caller
document.write(xFunction(1, 10) + " - " + typeof(xFunction(1, 10)))
Output
Why Currying is Useful
let's say we need 2 instances of the xFunction
one that adds 10 to a given number and another that adds 20 to a given number.
Instead of creating new functions in case of using a regular function like the example below
// 1
// Regular function to increase a given number by 10
function increaseBy10(number){
// Return the result to the caller
return number + 10;
};
// The caller to increase a given number by 10
document.wrtie(increaseBy10(20)); // 120
// 2
// Regular function to increase a given number by 20
function increaseBy20(number){
// Return the result to the caller
return number + 20;
};
// The caller to increase a given number by 20
document.write(increaseBy20(100)); // 120
What if we need up to 6 instances of the xFunction
? that will result in having 6 bunches of the function block, we can achieve this seamlessly with less line of code by using currying, update the curried xFunction
to the code below
Example 6
// Curried function
function xFunction(number1){
return function(number2){
// Return the sum of number1 and number2 to the caller
return number1 + number2
};
};
// Set the xFunction argument to 10 by default - instance of xFunction
const increaseBy10 = xFunction(10);
// Caller to increase 1 by the ```increaseBy10``` function
document.write(increaseBy10(1) + " - " + typeof(increaseBy10(1)));
Explanation
1.
We assigned xFunction
a default argument of 10 which will be stored in the Lexical Environment to be accessed by the next function.
This enables nested functions within the
xFunction
to remember or have access to the upper variables (10 in this case).
2.
We stored the returned value (the next function) to a variable named increaseBy10
(citizenship).
xFunction
returns the next function(currying) to theincreaseBy10
variable
3.
We then call the increaseBy10
and passed a value of 1 as an argument to it.
increaseBy10
represents the next function
Example 7
function xFunction(number1){
return function(number2){
// Return the sum of number1 and number2 to the caller
return number1 + number2
};
};
// Set the xFunction argument to 20 by default - instance of xFunction
const increaseBy20 = xFunction(20);
// Caller to increase 30 by ```increaseBy20``` function
document.write(increaseBy10(30) + " - " + typeof(increaseBy10(30)));
Output
More examples of nested functions
Example 8
Three (3) nested functions.
// Function that adds 3 given numbers
function sum3Numbers(number1) {
return function(number2){
return function(number3) {
// Return the sum of the 3 given numbers to the caller
return number1 + number2 + number3
}
}
}
// The caller
document.write(sum3Numbers(800)(9)(7) + " - " + typeof sum3Numbers(9)(8)(7))
Output
Example 9
An instance of sum3Numbers
a three (3) nested function.
// Function that adds 3 given numbers
function sum3Numbers(number1) {
return function(number2){
return function(number3) {
// Return the sum of the 3 given numbers to the caller
return number1 + number2 + number3
}
}
}
// Prefilled function 1 and first 2
const provideNumber3Only = sum3Numbers(1)(2)
// The caller
document.write(provideNumber3Only(0) + " - " + typeof provideNumber3Only(0))
Example 10
Real-life use case
// Function that registers a new developer
function newDeveloperRegistration (level){
return function(stack){
return function(nickname){
return function(twitterUrl){
// Generate developer profile
developerProfile = (level + " " + stack + " " + nickname + " connect on " + twitterUrl)
// Return developer profile to the caller
return developerProfile
}
}
}
}
// Junior level instance
const juniorLevel = newDeveloperRegistration("Junior");
// Senior level with backend stack instance
const seniorLevelBackend = newDeveloperRegistration("Senior")("backend");
// Output 1
document.write(`Output 1 <br />`)
document.write(juniorLevel("Frontend Developer")("unclebigbay")("https://www.twitter.com/unclebigbay143"))
// To create space between the outputs
document.write(`<br />`)
document.write(`<br />`)
// Output 2
document.write(`Output 2 <br />`)
document.write(seniorLevelBackend("unclebigbay")("https://www.twitter.com/unclebigbay143"))
Output
Easy right?
Summary
Currying is the process of breaking a function with multiple arguments into a nested function that returns each of those arguments like converting
func(x, y, z)
into callablefunc(x)(y)(z)
Lexical Scope allows the next function to access the value or argument of the previous function.
You can make several instances of a curried function.
Currying helps reduce repeating the same argument that is been passed into a function all over again, by creating an instance of it.
Advanced JavaScript Currying Resources
If you would like to learn more about currying, below are my recommended material to study.
- JavaScript Currying Partials - Javascript info
- Deep Currying in 7 Mintutes - Freecodecamp
Wow, what a journey, I am glad you made it to the end of this article, if you enjoyed and learned from this article, I will like to connect with you, so you won't miss any of my upcoming articles.
Let's connect on
See you in the next article. Bye Bye πββοΈ
If you like my content, you can also buy me a coffee below.