What is functional Programming? A Beginner’s Guide to Writing Cleaner JavaScript Code


Introduction to functional programming
Do you find it hard to debug or test your JavaScript code due to the growth in the codebase (all files and code needed to run a software application), or do you ask yourself why you keep repeating the same code when you could write it once and reuse it across your entire codebase?
Functional programming (FP) falls under a broader category of programming paradigms known as declarative programming. It is a style that developers use to write clean, maintainable, and organized code, making computer programs easier to test and debug.
FP is structured just like functions in Mathematics. It takes an input, performs a calculation, and returns an output (result)
A JavaScript code example with notes that show how math and functional programming are connected.
Michaelson (2011) explains that functional programming has its roots in mathematics, particularly in lambda calculus, a formal system developed in the 1930s by Alonzo Church, where functions were used to solve problems cleanly and logically.
Some developers assume that the concept of FP makes code harder to understand. However, FP concepts like pure functions, immutability, and recursion can seem abstract. With practice, FP promotes code maintainability.
In this article, we will discuss the principles of functional programming and learn how to write cleaner, maintainable code.
Why does Functional Programming Matter?
Think of building software like running a busy restaurant kitchen. Every dish you serve is a program. The more complex the dish is, the more important it is to follow a clear recipe.
Now imagine a chaotic kitchen where the chef works differently, uses irregular ingredients, and operates without proper measurements and guidelines.
Sure, food might still come out, but it will be inconsistent. It will be challenging to rectify any issues with the food, and nearly impossible to replicate the exact taste and feel of the food if the need arises to open a second branch.
This is the problem with poorly structured code. It is unpredictable, hard to debug(find and fix mistakes in your code so it works correctly), difficult to scale, and almost impossible to maintain or reuse effectively.
However, FP runs like a disciplined and efficient kitchen. Here is why it matters and why you should consider learning how to write code following functional programming principles :
Reusability: You can reuse small functions across your codebase, saving time and reducing repetition. Functional programming promotes writing small, reusable functions like spices or chopped ingredients that can be used in multiple dishes.
Predictability: Just like a sauce always tastes the same when made right, pure functions give the same output every time for the same input.
Cleaner Code: It’s easier to read and reason about, just like following a written recipe.
Fewer Bugs: Since functions don’t depend on or change outside data(data that lives outside the function), there’s less room for mistakes. like cooking each dish at its table with its own set of ingredients, so nothing gets mixed up by accident.
Explanation of Key Concepts of Functional Programming
Pure Function
The term pure simply means unchanged or unmixed, and this idea applies to Functional programming as well. A pure function behaves just like a mathematical function. No hidden tricks, it always gives the same output for the same input.
What does this mean?
Imagine you have a machine that takes a number as input and produces an output with the number you give it.
That is exactly what a pure function can be likened to.
A pure function always gives the same result when you give it the same input.
Now, let us check some real examples of a function :
function square(x){
return x * x ;
}
The function named "square" multiplies the input number (represented as x) by itself.
For example, if you substitute x with 5 in the function above, it will always return 25 every single time, no matter what else is happening in the program.
Therefore:
square(2) means 2 × 2 = 4
square(5) means 5 × 5 = 25
Every time you give it 2, → it gives back 4.
Every time you give it 5, → it gives back 25.
Immutability
According to the Oxford Dictionary, the word ‘immutable’ means unchanging over time or unable to be changed.
Functional programming is built around the concept of immutability. It simply states that you should not change the value (A value is a piece of information a computer uses) once it has been assigned to a variable(In programming, a Variable is a name used to store a value). Instead of changing it, create a new version with the updated value.
Variables in FP behave like an equation in mathematics, where :
You equate a value to a name, and
The equation does not change
// This is a constant binding in Javascript --- like a math equation
const pi = 3.14
console.log(pi); // Output : 3.14
// Trying to change the value will throw an error
pi = 4.23; // Error
If you need a new value, create a new variable or a new version, rather than updating the old one.
In FP, if you write x = 2, it means x is 2, not that 2 is stored in the x variable.
The importance of this is that once you set x to 2, you’re not allowed to change it later and assign a new value to x.
Declarative and Imperative programming.
Declarative and imperative programming are both programming paradigms, that is, styles of writing code. They both describe different styles of giving computer instructions. While declarative programming focuses on what to do, imperative programming focuses on how it is done.
Imperative Programming:
Imperative programming is a style of instructing a computer or writing code that involves a step-by-step guide on how to carry out a task. This style of programming gives you power over the flow of your program. That is, you decide at every given point what should be done with the use of conditionals, loops, and mutable variables (variables that can change at any given time)
let numbers = [1,2,3,4,5];
let double = [];
for(let i = 0; i < number.length; i++){
double.push(numbers[i] * 2);
}
console.log(doubled);
code sample written using imperative programming in JavaScript
Explanation of the code above
This JavaScript code creates an array of numbers [1, 2, 3, 4, 5], loops through it(going through each number in the array one at a time), doubles each number, and stores the results in a new array called doubled.
Finally, it prints [2, 4, 6, 8, 10] to the console. The purpose is to transform the original list by multiplying each number by 2, which is a common task in programming when processing or transforming data.
Declarative Programming
Declarative programming is a style of writing code that focuses on the task a program should perform and not how it is done.
const numbers = [1,2,3,4,5,6];
const doubledEvents = numbers
.filter(num => num % 2 === 0) // FIlter even numbers
.map(num => num * 2) // Double each numbers
console.log(doubledEvents) //Output [4, 8, 12]
code sample written using declarative programming in JavaScript
Explanation of the code above
Instead of showing step-by-step how to loop through the array, check each number, and store results manually (like we did in the imperative programming code sample above), this code simply declares what should happen using .filter() and .map().
This hides the complex details, such as setting up a loop, managing counters, or pushing into a new array, and lets JavaScript handle all that for you.
Stateless function
A stateless function means a function that does not rely on any variable outside itself. It only uses the input you give it.
function multiply(a, b){
return a * b
}
The function above does not use any data outside of it. It only makes use of the two numbers you pass into the function. If you declare a = 8 and b = 10. You will always get the product of 8 and 10 ( 8 * 10 ), which is 80.
However, here is an example of a stateful function (opposite of a stateless function) :
let x = 10;
function multiplyWithX(a){
return a * x; // uses external variable 'x'
}
This function makes use of the x variable, which is outside the multiplyWithX function.
First-Class Function
In Functional programming, the term “first-class function” means that functions are treated like numbers, strings, or objects. Just like other data types like numbers, strings, or objects, functions can be assigned to a variable, passed as arguments to different functions, and returned as values from functions.
Which means you can :
Assign a function to a variable
const greet = function() {
console.log("Hello")
};
Assign a function to the variable called greet.
Pass as arguments to another function
function greet(){
return "Hello!";
}
function run(fn){
console.log(fn());
}
run(greet); // prints "Hello!"
Pass the greet function as an argument to the run function, and greet will print “Hello!”
Return as values from other functions
function createMultiplier(x){
return function(y){
return x * y;
};
}
const timesTwo = createMultiplier(2);
console.log(timesTwo(5)); // prints 10
The function createMultiplier returns another function, not just a number or string
Recursion instead of a Loop
In functional programming, recursion is used instead of a loop because FP doesn't encourage changing data after it has been created.
What is a loop?
A Loops enable a computer to carry out the same task over and over until a certain requirement is fulfilled.
for(let i = 1; i <= 5; i++){
console.log("Picked orange" + 1);
}
Explanation of the code above
The code instructs the computer to start counting from 1 to 5. On the first count, it picks one orange. The number of oranges it has picked matches the current round. That is, on the 4th time, it has picked 4 oranges. On the 5th count, it will pick the fifth orange.
Here’s what each part means:
Let i = 1 — the computer starts counting from 1. i keeps track of the current count or round.
i <= 5 — it keeps picking oranges as long as i is 5 or less.
i++ — after picking an orange, it says “Let’s move to the next one” by increasing the count by 1.
Inside the loop:
console.log("Picked orange " + i) — Console.log prints which orange was picked in that round.
👉 Notice: The value of i is updated each time, meaning the data (i) is changed, which functional programming tries to avoid.
How is recursion used in FP instead of a loop?
Instead of updating the value of 'i' in a loop, recursion creates a new set of variables with each call by passing a new value as an argument to the next function call.
Lazy evaluation
It is a strategy in functional programming that is used to delay the execution of a logic until its results are required.
Lazy evaluation allows a program to store an expression (such as a function call or mathematical operation) without computing its value immediately. The expression is only evaluated when the program needs the result. For example, when it is printed to the console and web pages, assigned to a variable, or used in a calculation. This helps avoid unnecessary computations.
// Lazy evaluation (delayed using function)
function lazyAdd(a, b){
return () => a + b; // Return a function instead of computing directly
}
const lazyResult = lazyAdd(3, 4); // not computed yet
console.log(lazyResult()); // Now it computes and outputs
Side Effects in Functional Programming
A side effect refers to any change a function makes to external states or systems outside itself, like :
modifying state
let counter = 0 ; // global state
function increment(){
counter++; // modifies state outside the function
}
The function increment() changes the value of the counter, which exists outside its own scope.
printing output into the console or user screen
function greet(){
console.log("Hello, world!"); // prints output
}
console.log causes an observable effect. It shows text on the screen or console
calling APIs(Application Programming Interface) ; interacting with an external system or service
function fetchUser(){
fetch("https://api.example.com/user") // calls an API
.then(response => response.json())
.then(data => console.log(data));
}
fetch() sends a request to the internet (external world), which is outside the function’s control.
Other forms of side effects include:
Writing to a file
interacting with the DOM, or the user interface
Functional programming discourages the use of functions that cause side effects. It rather encourages pure Functions( functions without side effects)
Why are side effects discouraged in functional programming?
In functional programming, avoid side effects in functions to keep your code cleaner and more reliable.
But side-effects are not bad. They are unavoidable in real-world applications. Without it, you cannot build useful software.
Functional Programming Needs Side Effects. Here’s How to Use Them Wisely;
- Keep Side Effects outside the main logic
Functional programming encourages you to keep side effects (API calls, or changing values) outside the core part of your code, not inside the logic that makes decisions and calculations
Example :
Instead of doing this :
function getUserData(){
fetch("https://api.com/user"); // side effect inside logic
}
You do this :
function processUserData(data){
// pure logic
return data.name.toUpperCase();
}
fetch("https://api.com/user") // side-effects outside the function
.then(processUserData)
.then(console.log);
Fetching and logging are side effects, but they don’t happen inside the processUserData function.
Functional Programming vs Object-Oriented Programming
Functional Programming and object-oriented programming are both programming paradigms. That is, they are methods of structuring code and solving logical problems. However, they differ in how they organize and execute lines of code.
You can examine the differences between Functional Programming(FP) and Object Oriented programming(OOP ) through their core concept and building blocks
Core Concept of Functional and Object-Oriented Programming
Core Concept of Functional Programming(FP)
FP focuses on writing code using pure functions. It avoids shared state and avoids changing data (also called mutable data)
// Pure function: it depends only on inputs, not on outside variables
function add(a, b){
return a + b;
}
// Avoiding mutable data : instead of changing the array, return a new one
function addItemToList(list, item){
return [...list, item] // returns a new array with item added
}
// Using the functions
const originalList = [1,2,3];
const newList = addItemToList(originalList, 4);
console.log("Original List:", originalList); // [1,2,3] not changed
console.log("New List:", newList); // [1,2,3,4]
Core Concept of Object-Oriented Programming(OOP)
Unlike Functional Programming, which focuses on pure functions and immutable data, Object-Oriented Programming (OOP) is built around objects. These objects group related data and methods together using classes.
// This is the class - used to group data and methods
class Dog{
// This is a method - a function related to the object
bark(){
console.log("Woof!");
}
}
// This is an object created from the class
const myDog = new Dog();
// Calling a method on the object
myDog.bark(); //Output : Woof!
Building Blocks of Functional and Object-Oriented Programming
The Building Block of Functional Programming (FP)
The main building blocks in FP are functions. These functions take inputs and return outputs without changing anything outside themselves. They don’t rely on or modify external values, which makes them predictable and easy to test.
function add(a, b){
return a + b;
}
const result = add(2, 3);
console.log(result); // Output:5
The Building Block of Object-Oriented Programming (OOP)
Object-Oriented Programming (OOP) is built around classes and objects. Each object contains related data (properties) and methods (functions) that work on that data.
class Dog{
constructor(name){
this.name = name; // related data (property)
}
bark(){
console.log(this.name + "says Woof!"); // method uses the data
}
}
const myDog = new Dog("Bingo");
myDog.bark(); // Output: Bingo says Woof!
Real-life examples of functional programming
Functional programming may sound technical, but it’s a common approach used by software developers to write clean and reliable code. Let’s look at two simple real-life examples to understand how it works.
Filtering Emails (Using Higher-Order Functions)
Scenario: A user wants to see only unread emails.
// Immutable data - the original array is not changed
const emails = [
{subject: "Welcome!", read: true},
{subject: "New Offer!", read: false},
{subject: "Reminder", read: false}
];
// Using a higher-order function (filter)
// The callback is a pure function - it doesn't change anything outside itself
const unreadEmails = emails.filter(email => !email.read);
console.log(unreadEmails);
// Output: [{ subject: "New Offeer!"}, { subject: "Reminder"}]
// Declarative style - clearly describes what we want (filter unread emails)
Functional programming shines in data filtering and transformation like this.
Transforming User Input (Map Function)
Scenario: You receive an array of user names and want to capitalize them.
// Immutable data - the origin array "users" is not changed
const users = ["isabella" , "james", "bolu"];
// Higher-order function - "map" takes a function as an argument
// Pure function - the callback depends only on input and returns a new value without side effects
const capitalized = users.map(name => name.toUpperCase());
console.log(capitalized);
// ["ISABELLA", "JAMES", "BOLU"]
// Declarative style - clearly expresses what we want: uppercase names
This is a stateless, functional transformation using .map().
Conclusion
In this article, you have learned the major concepts of functional programming using the JavaScript programming language.
As you continue your programming journey, these concepts will form the foundation for writing cleaner and maintainable code.
Subscribe to my newsletter
Read articles from Adeyeye Boluwatife directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Adeyeye Boluwatife
Adeyeye Boluwatife
I am a technical writer specializing in transforming complex technical topics into clear, engaging content that educates and empowers users. With a background in web development and MERN stack projects, I bring deep technical knowledge to every piece I write ensuring accuracy and clarity for both technical and non-technical audiences. I create: API documentation Technical blog posts Tutorials and guides Product manuals