JavaScript: Programación funcional
Descubre los fundamentos y técnicas de programación funcional en JavaScript para crear código limpio, inmutable y eficiente.
Aprende JavaScript GRATIS y certifícateProgramación funcional en JavaScript
La programación funcional representa un paradigma de desarrollo que trata las funciones como elementos de primera clase, permitiendo crear código más predecible, mantenible y libre de efectos secundarios. En JavaScript, este enfoque ha ganado popularidad debido a su capacidad para simplificar operaciones complejas y mejorar la legibilidad del código.
Fundamentos del paradigma funcional
JavaScript soporta múltiples paradigmas de programación, siendo la programación funcional uno de los más expresivos. Este paradigma se basa en el concepto matemático de funciones, donde cada función produce una salida determinística basada únicamente en sus entradas, sin modificar el estado externo.
Las funciones puras constituyen el pilar fundamental de este paradigma. Una función pura siempre devuelve el mismo resultado para los mismos argumentos y no produce efectos secundarios observables:
// Función pura
function sumar(a, b) {
return a + b;
}
// Función impura (modifica estado externo)
let contador = 0;
function incrementar() {
contador++; // Efecto secundario
return contador;
}
La inmutabilidad es otro concepto clave que evita la modificación directa de datos existentes, creando nuevas estructuras en su lugar:
// Enfoque inmutable
const numeros = [1, 2, 3];
const nuevosNumeros = [...numeros, 4]; // Crea nuevo array
// En lugar de modificar el original
// numeros.push(4); // Esto sería mutable
Funciones de orden superior
Las funciones de orden superior son aquellas que reciben otras funciones como argumentos o devuelven funciones como resultado. JavaScript proporciona métodos nativos que implementan este concepto de manera elegante.
El método map() transforma cada elemento de un array aplicando una función:
const precios = [10, 20, 30];
const preciosConIVA = precios.map(precio => precio * 1.21);
console.log(preciosConIVA); // [12.1, 24.2, 36.3]
El método filter() selecciona elementos que cumplen una condición específica:
const productos = [
{ nombre: 'Laptop', precio: 800 },
{ nombre: 'Mouse', precio: 25 },
{ nombre: 'Teclado', precio: 60 }
];
const productosCaros = productos.filter(producto => producto.precio > 50);
El método reduce() combina todos los elementos de un array en un único valor:
const ventas = [100, 200, 150, 300];
const totalVentas = ventas.reduce((total, venta) => total + venta, 0);
console.log(totalVentas); // 750
Composición de funciones
La composición de funciones permite combinar funciones simples para crear operaciones más complejas. Este enfoque promueve la reutilización y facilita el testing:
const multiplicarPorDos = x => x * 2;
const sumarCinco = x => x + 5;
const elevarAlCuadrado = x => x * x;
// Composición manual
const procesarNumero = x => elevarAlCuadrado(sumarCinco(multiplicarPorDos(x)));
console.log(procesarNumero(3)); // ((3 * 2) + 5)² = 121
Para mejorar la legibilidad, podemos crear una función compose que automatice este proceso:
const compose = (...funciones) => valor =>
funciones.reduceRight((acc, fn) => fn(acc), valor);
const procesarNumero = compose(
elevarAlCuadrado,
sumarCinco,
multiplicarPorDos
);
Closures y funciones parciales
Los closures permiten que las funciones mantengan acceso a variables de su ámbito léxico, incluso después de que el ámbito padre haya terminado su ejecución:
function crearContador(inicial = 0) {
let contador = inicial;
return function() {
contador++;
return contador;
};
}
const contador1 = crearContador(5);
console.log(contador1()); // 6
console.log(contador1()); // 7
La aplicación parcial permite crear nuevas funciones fijando algunos argumentos de una función existente:
function multiplicar(a, b, c) {
return a * b * c;
}
// Función que aplica parcialmente el primer argumento
const multiplicarPorDos = multiplicar.bind(null, 2);
console.log(multiplicarPorDos(3, 4)); // 2 * 3 * 4 = 24
Manejo funcional de arrays
JavaScript ofrece un conjunto robusto de métodos para el manejo funcional de arrays que eliminan la necesidad de bucles tradicionales:
const estudiantes = [
{ nombre: 'Ana', edad: 22, notas: [8, 9, 7] },
{ nombre: 'Carlos', edad: 20, notas: [6, 8, 9] },
{ nombre: 'María', edad: 23, notas: [9, 9, 8] }
];
// Encadenamiento de operaciones funcionales
const promediosAltos = estudiantes
.map(estudiante => ({
...estudiante,
promedio: estudiante.notas.reduce((sum, nota) => sum + nota, 0) / estudiante.notas.length
}))
.filter(estudiante => estudiante.promedio >= 8)
.map(estudiante => estudiante.nombre);
console.log(promediosAltos); // ['Ana', 'María']
El método flatMap() combina las operaciones de mapeo y aplanamiento:
const frases = ['Hola mundo', 'JavaScript funcional'];
const palabras = frases.flatMap(frase => frase.split(' '));
console.log(palabras); // ['Hola', 'mundo', 'JavaScript', 'funcional']
Gestión de estado inmutable
La gestión de estado inmutable evita modificaciones directas de objetos y arrays, creando nuevas versiones en su lugar:
const estadoInicial = {
usuario: { nombre: 'Juan', edad: 25 },
configuracion: { tema: 'claro', idioma: 'es' }
};
// Actualización inmutable usando spread operator
function actualizarUsuario(estado, nuevosDatos) {
return {
...estado,
usuario: {
...estado.usuario,
...nuevosDatos
}
};
}
const nuevoEstado = actualizarUsuario(estadoInicial, { edad: 26 });
Para estructuras más complejas, podemos crear funciones auxiliares que faciliten las actualizaciones inmutables:
function actualizarEnRuta(objeto, ruta, valor) {
const [cabeza, ...cola] = ruta;
if (cola.length === 0) {
return { ...objeto, [cabeza]: valor };
}
return {
...objeto,
[cabeza]: actualizarEnRuta(objeto[cabeza], cola, valor)
};
}
const estadoActualizado = actualizarEnRuta(
estadoInicial,
['configuracion', 'tema'],
'oscuro'
);
Lecciones de este módulo de JavaScript
Lecciones de programación del módulo Programación funcional del curso de JavaScript.
Ejercicios de programación en este módulo de JavaScript
Evalúa tus conocimientos en Programación funcional con ejercicios de programación Programación funcional de tipo Test, Puzzle, Código y Proyecto con VSCode.