Skip to content

RESOURCES / BLOG

What Is Functional Programming in JavaScript?

JavaScript developers often swap tips in threads about code that is easier to test, change, and scale. A recurring topic is functional programming and how it compares to more traditional OOP-style code.

What is functional programming in JavaScript? How does it differ from the typical class-based approach, and what practical patterns should I use in real projects?

I’m especially interested in pure functions, immutability, composition, and how these ideas apply to things like API data, UI state, or building image and video URLs. Any examples are appreciated.

Functional programming in JavaScript is a style that focuses on building programs by composing small, pure functions that transform data. Instead of mutating state and relying on side effects, you write functions that always return the same output for the same input and avoid changing external variables.

  • Pure functions: No side effects; same inputs produce the same output.
  • Immutability: Do not modify existing objects or arrays. Return new ones instead.
  • Higher-order functions: Functions that take or return other functions.
  • Composition: Build bigger behavior by combining small functions.
  • Declarative style: Express what you want, not how to do it step by step.

Pure function and immutability:

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

// Immutable update
const addTag = (post, tag) => ({
  ...post,
  tags: [...post.tags, tag]
});

const original = { id: 1, tags: ["js"] };
const updated  = addTag(original, "fp");
// original stays unchangedCode language: JavaScript (javascript)

Higher-order functions and composition:

// Higher-order function
const withLogging = fn => (...args) => {
  console.log("calling with", args);
  const result = fn(...args);
  console.log("result", result);
  return result;
};

// Compose utility
const compose = (...fns) => x => fns.reduceRight((v, f) => f(v), x);
const pipe    = (...fns) => x => fns.reduce((v, f) => f(v), x);

// Example pipeline
const trim = s => s.trim();
const lower = s => s.toLowerCase();
const slugify = s => s.replace(/\s+/g, "-");

const toSlug = pipe(trim, lower, slugify);
toSlug("  Hello World  "); // "hello-world"Code language: JavaScript (javascript)

Declarative data transforms with map, filter, reduce:

const users = [
  { id: 1, name: "Ari", active: truescore: 42 },
  { id: 2, name: "Bea", active: false, score: 10 },
  { id: 3, name: "Cam", active: truescore: 60 }
];

const topActiveNames =
  users
    .filter(u => u.active)
    .filter(u => u.score >= 40)
    .map(u => u.name);
// ["Ari", "Cam"]

const totalScore =
  users.reduce((sum, u) => sum + u.score, 0);
// 112Code language: JavaScript (javascript)

Side effects like network requests are inevitable. Keep them at the edges and transform results with pure functions.

const parseUsers = data => data.users ?? [];
const active = us => us.filter(u => u.active);
const byName = us => us.map(u => u.name);

fetch("/api/users")
  .then(res => res.json())
  .then(pipe(parseUsers, active, byName))
  .then(names => console.log("Active:", names))
  .catch(console.error);Code language: JavaScript (javascript)
  • Predictability: Pure functions are easy to test and reason about.
  • Refactor friendly: Composition keeps changes localized.
  • Performance wins: Clear data pipelines help you find where to optimize. See how this fits into overall web performance.

URL generation is a great fit for pure functions: an input object maps to a stable image URL. You can build composable helpers that add transformations without mutating state.

// A generic, composable URL builder pattern
const join = (sep, parts) => parts.filter(Boolean).join(sep);

const transform = parts => join(",", parts);
const withSize  = (w, h, mode = "c_fill") => transform([`w_${w}`, `h_${h}`, mode]);
const quality   = q => transform([`q_${q}`]);
const format    = f => transform([`f_${f}`]);

const buildUrl = ({ cloud, publicId, transforms = [] }) =>
  `https://res.cloudinary.com/${cloud}/image/upload/${join(",", transforms)}/${publicId}`;

const thumb = pipe(
  () => [withSize(320, 320), quality("auto"), format("auto")],
  transforms => ({ cloud: "demo", publicId: "sample.jpg", transforms })
);

buildUrl(thumb());
// https://res.cloudinary.com/demo/image/upload/w_320,h_320,c_fill,q_auto,f_auto/sample.jpgCode language: JavaScript (javascript)

Choosing the right output format is also a pure decision based on capabilities. For example, modern formats can lower bandwidth while keeping quality. If you are weighing options, this guide on WebP format technology is a helpful overview.

You can keep everything functional while using Cloudinary. Treat transformations as data, compose them, and map over lists of assets to produce deterministic URLs. That pairs well with responsive UIs and serverless functions.

// Map a gallery of product images to optimized variants
const toVariant = (size) => (img) => buildUrl({
  cloud: "demo",
  publicId: img.publicId,
  transforms: [withSize(size, size), quality("auto"), format("auto")]
});

const gallery = [{ publicId: "shoes/red" }, { publicId: "shoes/blue" }];

const small  = gallery.map(toVariant(300));
const medium = gallery.map(toVariant(600));Code language: JavaScript (javascript)

For quick experiments or manual conversions while prototyping a pipeline, check the curated Cloudinary tools. As you iterate, understanding format choices helps, and the WebP guide above provides the tradeoffs.

  • Avoid mutating arrays or objects in place. Prefer spreads or methods that return new values.
  • Keep I/O at the boundary. Transform data separately from fetching or rendering.
  • Don’t over-abstract. Compose a few small utilities rather than a deep hierarchy.
  • Write pure functions, avoid shared mutable state, and compose behavior from small pieces.
  • Use map, filter, and reduce for clear data pipelines.
  • Treat media URLs as pure outputs from input data. See image URL concepts and weigh modern formats like WebP with this guide.
  • For broader performance context, read about optimized websites, and try the Cloudinary tools for quick transformations.

Ready to apply functional patterns to your media pipeline and delivery? Sign up for Cloudinary free and start building composable, high-performance image and video workflows.

Start Using Cloudinary

Sign up for our free plan and start creating stunning visual experiences in minutes.

Sign Up for Free