Skip to main content

Command Palette

Search for a command to run...

Functional Programming in JavaScript – Functions as First-Class Citizens

Updated
7 min readView as Markdown

Yesterday, I explored JavaScript Prototypes and Prototypal Inheritance and understood how JavaScript's object system works underneath the class syntax.

Today, I shifted my focus from objects and inheritance to another important programming style:

Functional Programming.

JavaScript treats functions as first-class citizens, which means functions can be stored in variables, passed as arguments, and returned from other functions.

I explored:

  • First-Class Functions

  • Callback Functions

  • Higher-Order Functions

  • Pure Functions

  • Side Effects

  • map()

  • filter()

  • reduce()

  • forEach()

Let's dive in.


What is Functional Programming?

Functional Programming (FP) is a programming style where functions are treated as the primary building blocks of a program.

Instead of focusing mainly on changing data and object state, functional programming often emphasizes:

  • Reusable functions

  • Predictable behavior

  • Avoiding unnecessary side effects

  • Transforming data

  • Composing smaller functions

JavaScript supports functional programming because functions are first-class values.


Functions Are First-Class Citizens

In JavaScript, functions can be treated like any other value.

We can store a function inside a variable:

const greet = function () {

    console.log("Hello!");

};

Then call it:

greet();

We can also store an arrow function:

const add = (a, b) => a + b;

console.log(add(10, 20));

Functions can therefore be:

  • Stored in variables

  • Passed to other functions

  • Returned from functions

  • Stored inside arrays and objects


Passing Functions as Arguments

We can pass a function to another function.

function greetUser(name) {

    console.log(`Hello ${name}`);

}

function processUser(callback) {

    callback("Saurabh");

}

processUser(greetUser);

Here:

greetUser
    ↓
passed to
    ↓
processUser
    ↓
callback()

This is the foundation of callback functions.


What is a Callback Function?

A callback is a function passed into another function so that it can be executed later or at a specific point.

Example:

function calculate(a, b, callback) {

    return callback(a, b);

}

function add(a, b) {

    return a + b;

}

console.log(
    calculate(10, 20, add)
);

Output:

30

The add function is being passed as a callback.


Higher-Order Functions

A higher-order function is a function that:

  • Accepts another function as an argument

  • Returns a function

  • Or does both

Example:

function operate(a, b, operation) {

    return operation(a, b);

}

const result = operate(
    10,
    5,
    (a, b) => a * b
);

console.log(result);

Here operate() is a higher-order function because it accepts another function.


Why Higher-Order Functions Matter

Higher-order functions allow us to create reusable logic.

Instead of writing:

function addNumbers(a, b) {
    return a + b;
}

function multiplyNumbers(a, b) {
    return a * b;
}

we can create a generic operation:

function calculate(a, b, operation) {

    return operation(a, b);

}

Now the behavior can be changed by passing different functions.


Pure Functions

A pure function is a function that:

  1. Produces the same output for the same input.

  2. Doesn't modify external state or cause observable side effects.

Example:

function add(a, b) {

    return a + b;

}

Every time we call:

add(10, 20);

we get:

30

The function doesn't depend on outside variables.


Impure Functions

Consider:

let total = 0;

function addToTotal(amount) {

    total += amount;

}

The function modifies external state.

Its behavior depends on the current value of total.

This makes it an impure function.

Impure functions aren't always bad, but understanding side effects helps us control application complexity.


What are Side Effects?

A side effect is something a function does beyond simply returning a value.

Examples include:

  • Changing a global variable

  • Modifying an object outside the function

  • Updating the DOM

  • Writing to storage

  • Making an API request

  • Logging to the console

For example:

document.body.textContent = "Hello";

This changes something outside the function's return value.


Array Methods

Functional programming becomes especially useful when working with arrays.

JavaScript provides methods such as:

map()
filter()
reduce()
forEach()

These methods commonly accept callback functions.


forEach()

forEach() executes a function once for every element.

const numbers = [1, 2, 3, 4];

numbers.forEach((number) => {

    console.log(number);

});

Output:

1
2
3
4

forEach() is useful when we want to perform an action for each item.


map()

map() creates a new array by transforming each element.

const numbers = [1, 2, 3, 4];

const doubled = numbers.map(
    number => number * 2
);

console.log(doubled);

Output:

[2, 4, 6, 8]

The original array remains unchanged.


filter()

filter() creates a new array containing only elements that satisfy a condition.

const numbers = [
    1, 2, 3, 4, 5, 6
];

const evenNumbers = numbers.filter(
    number => number % 2 === 0
);

console.log(evenNumbers);

Output:

[2, 4, 6]

reduce()

reduce() is used to combine array elements into a single accumulated value.

For example, calculating a total:

const numbers = [10, 20, 30];

const total = numbers.reduce(
    (sum, number) => sum + number,
    0
);

console.log(total);

Output:

60

The second argument:

0

is the initial accumulator value.


map() vs filter() vs reduce()

Method Purpose Returns
forEach() Perform an action undefined
map() Transform elements New array
filter() Select elements New array
reduce() Combine elements Single value

A simple way to remember them:

map     → Transform
filter  → Select
reduce  → Combine
forEach → Perform an action

Chaining Array Methods

We can combine these methods.

Example:

const numbers = [
    1, 2, 3, 4, 5, 6
];

const result = numbers
    .filter(number => number % 2 === 0)
    .map(number => number * 2);

console.log(result);

Output:

[4, 8, 12]

The process is:

Original Array
      ↓
   filter()
      ↓
Even Numbers
      ↓
    map()
      ↓
Doubled Numbers

This style is extremely common in modern JavaScript.


Functional Programming and React

These concepts become especially important when working with React.

For example:

const names = users.map(
    user => user.name
);

Or filtering data:

const activeUsers = users.filter(
    user => user.active
);

These patterns appear constantly when building user interfaces.


Avoiding Mutation

Functional programming often encourages avoiding unnecessary mutation.

Instead of:

const numbers = [1, 2, 3];

numbers.push(4);

we can create a new array:

const numbers = [1, 2, 3];

const updatedNumbers = [
    ...numbers,
    4
];

Now the original array remains unchanged.

This idea becomes particularly important when working with React state.


Best Practices

✔ Keep functions small and focused.

✔ Prefer pure functions when practical.

✔ Avoid unnecessary mutation.

✔ Use map() for transformation.

✔ Use filter() for selection.

✔ Use reduce() for accumulation.

✔ Use forEach() when you simply need to perform an action for each element.

✔ Use meaningful callback parameter names.


My Biggest Takeaway

Today, I learned that JavaScript functions are much more powerful than simply blocks of reusable code.

Because functions are first-class values, I can pass them around, return them, and use them to build flexible abstractions.

The array methods were especially important:

map() → Transform

filter() → Select

reduce() → Combine

forEach() → Perform an action

These concepts are going to be extremely useful as I move toward React, because modern frontend development relies heavily on transforming and rendering collections of data.

100 Days of Code: My Journey to Becoming a Full Stack Developer

Part 1 of 50

Welcome to my 100 Days of Code journey! In this series, I'll document my daily progress as I learn Full Stack Web Development from the ground up. Every post will cover what I learned, challenges I faced, mistakes I made, and the projects I built. My goal is not just to complete 100 days but to become a better developer through consistency, discipline, and learning in public. Topics I'll cover include: • Git & GitHub • HTML, CSS & JavaScript • React.js • Node.js & Express • MongoDB • APIs • Real-world Projects • AI tools for Developers Whether you're just starting out or revising your fundamentals, I hope this journey helps you learn alongside me. Let's build, learn, and grow together! 🚀

More from this blog

T

TheSaurceCode

73 posts

Documenting my journey to becoming a Full Stack Developer through daily blogs, coding challenges, projects, tutorials, and lessons learned. Learn, build, and grow with me