Imagine a laboratory in Jurassic Park where every experiment on dinosaur DNA always produces the same result given the same input data. There are no side effects - no dinosaur escapes, no security system is accidentally disabled. This is exactly how functional programming (FP) works - it's a paradigm where code behaves like a controlled scientific experiment.
In imperative programming, we tell the computer how to do something step by step. In functional programming, we describe what we want to achieve, using functions as the fundamental building blocks.
1// Imperative approach - step by step
2const dinosaurs = ['T-Rex', 'Velociraptor', 'Triceratops', 'Stegosaurus'];
3const carnivores = [];
4for (let i = 0; i < dinosaurs.length; i++) {
5 if (dinosaurs[i] === 'T-Rex' || dinosaurs[i] === 'Velociraptor') {
6 carnivores.push(dinosaurs[i]);
7 }
8}
9
10// Functional approach - declarative
11const isCarnivore = (name) => ['T-Rex', 'Velociraptor'].includes(name);
12const carnivoresFP = dinosaurs.filter(isCarnivore);A pure function is a controlled experiment - given the same input data, it always returns the same result and causes no side effects.
1// PURE FUNCTION - always the same result
2function calculateDangerLevel(weight, speed, aggression) {
3 return (weight * 0.3) + (speed * 0.3) + (aggression * 0.4);
4}
5
6// The same function called 1000 times with the same arguments
7// will always return the same result
8calculateDangerLevel(8000, 40, 95); // always 2465
9calculateDangerLevel(8000, 40, 95); // always 2465
10
11// IMPURE FUNCTION - modifies external data
12let totalDinosaurs = 0;
13function addDinosaur(name) {
14 totalDinosaurs++; // side effect - modifies external variable!
15 return { name, id: totalDinosaurs };
16}
17// Each call produces a different result, even with the same argument
18addDinosaur('Rex'); // { name: 'Rex', id: 1 }
19addDinosaur('Rex'); // { name: 'Rex', id: 2 } - different result!Immutability is the principle that once created, data is never changed. Instead of modifying an existing object, we create a new copy with changes. It's like creating a new DNA sequence instead of modifying an existing one - safer and more predictable.
1// MUTATION - dangerous (modifying the original object)
2const dinosaur = { name: 'Rex', health: 100 };
3dinosaur.health = 80; // The original object has been changed!
4
5// IMMUTABILITY - safe (new object)
6const dinosaurSafe = { name: 'Rex', health: 100 };
7const injuredDinosaur = { ...dinosaurSafe, health: 80 };
8// dinosaurSafe still has health: 100 (unchanged)
9// injuredDinosaur has health: 80 (new object)In JavaScript, functions are first-class citizens - you can assign them to variables, pass them as arguments, and return them from other functions.
1// Function assigned to a variable
2const classify = (dino) => dino.diet === 'carnivore' ? 'dangerous' : 'safe';
3
4// Function as an argument
5const dinosaurs = [
6 { name: 'Rex', diet: 'carnivore' },
7 { name: 'Brachio', diet: 'herbivore' },
8];
9const dangerous = dinosaurs.filter((dino) => classify(dino) === 'dangerous');
10
11// Function returning a function
12function createValidator(minWeight) {
13 return (dino) => dino.weight >= minWeight;
14}
15const isHeavyDino = createValidator(5000);
16isHeavyDino({ weight: 8000 }); // true
17isHeavyDino({ weight: 200 }); // false