Having been in the Javascript community for a while I’ve witnessed the building momentum towards a Functional Programming (FP) style. I think Javascript and FP are great but there is perhaps a misguided favor or emphasis put on FP as something superior. The React community help perpetuate this with the introduction of hooks, moving away from class based components (favoring functions) and libraries like Redux all employing bits of FP.
There is nothing wrong with embracing FP but there is an issue with proclaiming superiority especially when its an unfounded statement. One example of this bias being present is in a popular course on FP and JS Functional Programming For Beginners With JavaScript by James More. Overall not a bad course it covers some sound basics. But in chapter 6 when trying to illustrate the difference between Imperative vs Declarative (or Normal vs FP) a toxic view is presented. Two examples are given that just aren’t comparable and is crafted to favor FP. Then jQuery is mocked… which I’m not sure how jQuery even got brought up in this course, poor jQuery.
It seems harmless although whats troubling is this course is targeted to new and potentially easily influenced new comers. In this context I believe it establishes a divide or class hierarchy (pun intended) amongst developers. There is nothing wrong with jQuery, there is nothing wrong with imperative programming, FP is not better it’s different.
Lets break down the examples a little more and explore why they are a bad example to present newbies and not a fair comparison.
Declarative FP Example
// this is not line for line from James More code but a consolidated version that captures the esssence
const MEALS = [
{ description: "Breakfast", calories: 460 },
{ description: "Snack", calories: 180 },
...
]
const td = (className, children) => `<td class="${className}">${children}</td>`
// also in scope are functions like table, thead, tr
MEALS.map({ description, calories } => tr([td(description), td(calories)]))
This results in building up a table view to render as HTML. Its a nice approach using smaller functions to compose functionality.
The output:
<tr>
<td>Breakfast</td><td>460</td>
<td>Snack</td><td>180</td>
</tr>
Imperative non FP Example
The declarative approach is compared against this below “imperative” approach.
$("#app").append("<tr></tr>")
$("#app tr:last-child").append("<td>Breakfast</td><td>460</td>")
$("#app tr:last-child").append("<td>Snack</td><td>180</td>")
Whats wrong with these examples? They’re not comparable nor representative of imperative programming.
In the first example we have employed a data structure and sub routines which aren’t exclusive functional practices. Using data structures and functions are valid imperative programming techniques. This is designed to favor the FP example by omitting valid imperative constructs. The truth is there would be very little difference between these examples had both used the same available constructs (data structures and sub routines).
And jQuery is shamelessly laughed at. Why is jQuery even being used in this example? The introduction and support of querySelector predates map (if you consider map wasn’t available until IE11 querySelector was available in IE8). So if you can use map in the FP example you can drop jQuery altogether and use querySelector. It’s not about comparing FP to jQuery, this is comparing old JS to new JS, and mocking a library in the process that historically brought a lot of standardization to JS.
Then the argument is made you can’t compute the total calories in this imperative style of programming… Which it’s not, you’ve just hardcoded the output. It’s hard to compute anything when you have hardcoded the solution.
You could refactor the imperative example to a more succinct version.
document.querySelector("#app").append(`
<tr>
<td>Breakfast</td><td>460</td>
<td>Snack</td><td>180</td>
</tr>
`)
Essentially this is comparing the use of data structures and sub routines to hardcoding something, then claiming FP is better.
An Imperative C Example (without FP)
In fact the approach of breaking things into functions is so well established you can express the FP example in C. C being an imperative procedural language it often isn’t associated with FP. Its more verbose being a strict typed language. The Javascript is a little more concise in its handling of strings. The only real difference is in the iteration approach where this uses a for loop rather than map iteration.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct
{
char description[50];
int calories;
} Meal;
Meal meals[2] = {
{"Breakfast", 460},
{"Snack", 180}};
/* Wraps content in an HTML td tag. Uses calloc so the buffer is
zero-initialised — required for safe strcat chaining. */
char *td(char *className, char *children)
{
char *ret = calloc(1, 100);
strcat(ret, "<td class='");
strcat(ret, className);
strcat(ret, "'>");
strcat(ret, children);
strcat(ret, "</td>");
return ret;
}
int main()
{
int length, i;
length = sizeof(meals) / sizeof(Meal);
for (i = 0; i < length; ++i)
{
char cal[12];
snprintf(cal, sizeof(cal), "%d", meals[i].calories);
char *desc_cell = td("", meals[i].description);
char *cal_cell = td("", cal);
if (desc_cell && cal_cell)
{
printf("<tr>%s%s</tr>\n", desc_cell, cal_cell);
}
free(desc_cell);
free(cal_cell);
}
return 0;
}
FP slots into TypeScript naturally
The most useful FP techniques require no paradigm shift at all. They drop straight into everyday TypeScript alongside regular procedural code.
interface Meal {
description: string;
calories: number;
}
const meals: Meal[] = [
{ description: "Breakfast", calories: 460 },
{ description: "Snack", calories: 180 },
];
// These are FP primitives — they fit in any codebase without restructuring
const totalCalories = meals.reduce((sum, m) => sum + m.calories, 0);
const lightMeals = meals.filter(m => m.calories < 300);
const rows = meals.map(m =>
`<tr><td>${m.description}</td><td>${m.calories}</td></tr>`
);
map, filter, and reduce are pure functions — no side effects, predictable
output, easy to test. You don’t need to adopt immutability everywhere or reach
for a monad to get value from FP. These three alone cover the majority of
data-transformation work in a typical TypeScript codebase.
The useful mental model is a spectrum rather than a binary choice:
| Technique | FP concept | Adoption cost |
|---|---|---|
map / filter / reduce |
Pure functions, higher-order functions | Zero |
Immutable updates (...spread) |
Immutability | Low |
| Composing small single-purpose functions | Function composition | Low |
| Point-free style, currying | Partial application | Medium |
| Monads, applicatives, algebraic structures | Category theory | High |
The first three rows are worth adopting freely in any codebase. The further down
you go the more the surrounding code needs to follow suit for it to pay off.
Picking up map and filter doesn’t commit you to anything — it just makes
your data transformations cleaner and easier to reason about.
In closing
The issue with framing FP as a superior paradigm is that it sets up a false choice. The reality is that most experienced developers don’t write purely imperative or purely functional code — they reach for whatever is clearest for the problem at hand. Breaking things into small, focused functions is just good engineering, as the C example above illustrates. FP has given us excellent vocabulary and tooling for that, but the underlying principle predates it.
If you are interested in learning Functional Programming in Javascript, these two books take a pragmatic approach and are worth reading in full: