Functional programming, it sounds like something very high and complex concept, right? Don't worry, after reading this blog, you will understand the basic of functional programming(FP).
So let's start by outlining the topics we are going to learn about.
- What is abstraction?
- What is functional programming?
- What are the higher-order functions?
- Currying & chaining functions
- Some useful higher-order functions in JavaScript
- Let's summarize the above concepts
I think most of you guys are excited about learning what is FP? It's time to start now.
What is abstraction?
In everyday life, most of us don't pay attention to the devices we use for our daily purpose. I mean that we don't know how they work internally, do we? In the case of students and learners who are studying those devices or such things as we are learning about programming and JS. The normal people don't consider how their smartphones working and they don't need to consider either. Of course, the smartphone manufacturers hide those internal technical details from their target users. This is the definition of abstraction in a user-friendly way or in abstraction way for the normal people to understand. If we define it literally or in more CS manner, it means that when we work on apps or websites which are based on a large amount of data, we mostly focus on the detail and most important set of data from that large one. We don't need to focus on the data which are not related to our projects. We can see abstraction almost everywhere in real life.
If we go for admission to a school, college or any kind of academia, they will ask for your full name, your age, gender, grades and parents details like these. But they won't ask the colour you like most, your most favourite places, your favourite foods and your favourite Netflix shows I guess. They are working on a general and standard student model or student class for their particular school or university. And we as developers we have to know the abstraction which has a similar meaning in Computer Science. If you have got bored with text, let's review some code examples.
function Student(fullName,age,gender,grade,subjects) {
this.fullName = fullName;
this.age = age;
this.gender = gender;
this.grade = grade;
this.subjects = subjects;
}
/**
* This is a Student constructor which accept five arguments as
* properties for a student for a particular school or academia.
* This constructor should also access parental details but
* as an example, I'm not going far more details. But when we develop
* a program for students we might need to add those details further.
*/
What is functional programming?
How do you understand a function? If we think it mathematically like f(x) = y, it means that x is a variable and when we pass that x to function f, the result will be y. Whatever, it is a little bit daunting if we consider a function mathematically with all the staffs like domain, codomain, range and all. But if we think of Computer Science, it is a little bit similar. For example,
let myFavGames = [`Pottery`,`Car Racing`,`Loop`];
function favGame(gameList) {
console.log(`Your favourite games list is here`);
for(let i = 0; i < gameList.length; i++){
console.log(gameList[i]);
}
console.log(`Enjoy playing them`);
}
favGame(myFavGames);
The favGame
is a function which accepts gameList
as a parameter and obviously gameList
is a variable. Then the result or output from the function is just a bunch of sentences. This is just a normal function.
Then what is functional programming and is it different from the above functions. It is a programming paradigm like object-oriented programming and procedural programming. But we are going to focus on functional programming which is abbreviated as FP. There are some rules of thumb you have to follow.
- Immutability
- Statelessness
A pure function is a function which returns the same output every time you provide it with the same input. And it has to be immutable and stateless. It will be easy to understand with practical.
let myFavGames = [`Pottery`,`Car Racing`,`Loop`];
// Add a new element to the gameList array
function addGame(gameList,newGame){
let newArr = [...gameList];
newArr.push(newGame);
return newArr;
}
addGame(myFavGames,'Plants VS Zombies');
// Remove an element from the gameList array
function removeGame() {
myFavGames.pop()
}
removeGame();
In the above code box, we can see two functions called addGame
and removeGame
. The addGame
function is pure. If we put myFavGames
and Plants VS Zombies
as two arguments, it will return a new array which must be ['Pottery','Car Racing','Loop','Plants VS Zombies']
. If we see the second function which is removeGame
, it depends on the outer variable gameList
. It does not accept it as a parameter. It also removes a game name from the gameList
array that will mutate that variable. So we can say that removeGame
isn't a pure function because it causes side-effect. But can we say that addGame
is a pure function because it must return the same output if we provide it with the same input as many time as we want? Then, what about immutability? That function also has to be immutable to become a pure function. The addGame
function accepts myFavGames
as an argument so it is not directly depending on the myFavGames
variable. It also copies the gameList
array and creates a new array. Then do data processing on that new array instead of on the gameList. That means there is no side-effect by using the addGame
function.
The addGame
doesn't depend on any outer variable. This means it is stateless. If that function depends on any variable directly then it has dependent state. So we can say that our addGame
function is pure. Functional programming is all about using pure functions and working with first-class functions and higher-order functions. There is a list of pure functions provided by JavaScript.
let myFavGames = [`Pottery`,`Car Racing`,`Loop`];
console.log(myFavGames);
myFavGames.concat(`Angry Birds`); // return a new concated array
console.log(myFavGames);
myFavGames.slice(0,1); // return a new sliced array
console.log(myFavGames);
There are also other functions which we gonna talk about later.
What are the higher-order functions?
All of the above functions are examples of first-class functions. They simply accept numbers, strings, objects and other data types as arguments. In functional programming, first-class functions are treated as objects. So we can pass functions as arguments and return functions from functions. Higher-order functions use this technique. They accept one or more functions and other data types as arguments and return a function. This makes new possibilities for JavaScript developers. This functionality is also available in languages like Python, Haskell, Scala and they are all based on functional programming including JavaScript.
Currying & chaining functions
We can use method currying when we need to provide a function with multiple arguments but we can't put all the arguments at the same time. This is possible because of the help of closure. First, let see an example.
let myFavGames = [`Pottery`,`Car Racing`,`Loop`];
// Add a new element to the gameList array
function addGame(gameList){
return (gameName) => {
return gameList.concat(gameName);
}
}
addGame(myFavGames)('Plants VS Zombies');
let addANewGame = addGame(myFavGames);
console.log(addANewGame);
let newArr = addANewGame('Plants VS Zombies');
console.log(newArr);
Now, we are defining addGame
using the concept of currying function. We can use a function by passing multiple arguments one-by-one or as many as you want. In the above case, addGame
function accepts myFavGames
as a single argument and then return a function. Then the returned function accepts Plants VS Zombies
as its input then return a new favourite games list. Of course, you can use more and more functions inside another function as long as you can handle the complexities of code.
In the above example, you can see that we can use a currying function with all its arguments at the same statement or we can divide each or group of arguments as we want. So we have the advantage of using the specific part of the function when we need. To do so, we have to make sure the main function ( in the above case addGame
) is first needed to call with its parameters.
This is all about currying functions. This magic happens because of closure. So closure happens when a function access variables from its outer scope or parent scope. In the above code, the anonymous function ( the returned function ) can access the gameList
argument from its parent addGame
function. It is taking that variable from the parent function although the parent function is already returned. When a function is returned, it is removed from the execution stack. You can read more about the execution stack.
Then after this, we are going to chaining two or more functions. Chaining functions is just contacting one function with another function. That means when the first function is executed and the outputted result is go into the second function and being processed and so on and so forth.
const palindrome = (string) => {
let temp = string;
let tempReversed = temp.split('').reverse().join('');
return temp === tempReversed;
}
palindrome('mmxxmm'); // true
palindrome('MOM'); // true
palindrome('radar'); // true
palindrome('wxmdjwy'); // false
palindrome('umbrella'); // false
palindrome('cat'); // false
// We can simply do like below
let string = 'Hello World! This is the Chaining Function here!';
let newStr = string.split(' ').reverse().join(',,,,');
console.log(newStr);
// "here!,,,,Function,,,,Chaining,,,,the,,,,is,,,,This,,,,World!,,,,Hello"
console.log(string)
// "Hello World! This is Chaining Function here!"
Here, we chained split()
function to temp
string variable using .
operator. The dot operator is usually used as a chaining operator. Then, reverse()
function is chained behind split()
and then it is chained itself by join()
function. In the end, the result is a new string without any side-effects. So all of the three functions are pure functions. This is a basic example of chaining functions.
Some useful higher-order functions in JavaScript
Let's see some common higher-order functions.
let myFavGames = [`Pottery`,`Car Racing`,`Loop`];
// map()
let newGameList = myFavGames.map(e => e + '!!!');
console.log(newGameList);
console.log(myFavGames);
// filter()
newGameList = myFavGames.filter(e => e !== 'Loop');
console.log(newGameList);
console.log(myFavGames);
// reduce()
newGameList = myFavGames.reduce((item, e) => `${item},${e}`);
console.log(newGameList);
console.log(myFavGames);
// forEach()
myFavGames.forEach((e,i) => {
e = `${i+1} ${e}`;
console.log(e);
});
console.log(myFavGames);
These methods can be applied not only to string arrays but also to any type of arrays and other data types like string and objects. All of the above functions are all pure functions and they are all part of functional programming provide JavaScript. Firstly, map()
function just go through each element of the array and perform any processing on that element. Like this, the filter()
function filters the specific elements based on the provided callback function.
Likewise, the reduce()
function accumulates all of the elements of the array to a single value which we can assign to a variable. The first argument of the callback function is generally called accumulator
but you can name it as the way you want. After the first argument, the second is each element of the array. After that parameter, we can continue with another optional parameter called the index of each array's element.
The last but not least is the forEach()
function which simply loops through each element of the provided array. The first parameter represents each element of the array and the second one represent the index of the corresponding array's element. This pattern of parameter list is same as the map()
function and the filter()
function. These four functions are some of the most encountered functions throughout the functional programming in JavaScript.
Let's summarize the above concepts
First of all, the above concepts are interconnected to each other and these are just some parts of FP. Functional programming is all about working with functions. The higher-order functions make them a lot easier by providing abstraction and reducing code complexities. They enable us to write simpler code and easier to solve some sorts of problems. Most of JS developers use closures to provide modular programming i.e. we can make functions more securable and private using closures. Here is an instance of Modular Design Pattern.
let game = (function (){
let myFavGames = [`Pottery`,`Car Racing`,`Loop`];
return {
// Add a new element to the gameList array
addGame: function(newGame){
myFavGames.push(newGame);
},
// Remove an element from the gameList array
removeGame: function() {
myFavGames.pop()
},
// Show game array list
displayList: function() {
return myFavGames;
},
}
})();
This is how we can create private method. game
is an object and it has three methods. We can't access myFavGames
array because it is no more in the execution stack. The private function is returned an object and the game has only access to that object. We can use chaining to simplify codes and to write less code.
I hope now you get some basic insights into functional programming and how important it is. It is really helpful and makes coding more enjoyable. If you think I don't put the A Quote
section, please let me know your opinion. We can discuss more functional programming via the comments. Have a great day guys!!!🥳🤩😉
Top comments (0)