Higher Order Functions en JavaScript: funciones que reciben y devuelven funciones

En esta página
Enterate del próximo post
Un mail cuando publico algo nuevo. Sin spam y te podés dar de baja cuando quieras.

Un mail cuando publico algo nuevo. Sin spam y te podés dar de baja cuando quieras.
El post anterior sobre closures cerró señalando que crearSaludo y crearContador ya eran funciones de orden superior, sin que se las hubiera nombrado así todavía. Una función de orden superior es, sencillamente, una función que trata a otras funciones como datos: las recibe como parámetro, las devuelve, o hace las dos cosas a la vez.
function ejecutar(accion) {
accion();
}
function saludar() {
console.log("Hola");
}
ejecutar(saludar);
// Holasaludar se pasa a ejecutar sin los paréntesis de llamada: no se pasa el resultado de ejecutar saludar, se pasa la función misma, como un valor. ejecutar recibe ese valor bajo el nombre accion y recién ahí lo llama, con sus propios paréntesis. Una función, igual que un número o un string, puede guardarse en una variable, pasarse como argumento o devolverse desde otra función. Cualquier función que reciba una función como argumento, que devuelva una función, o las dos cosas, es una función de orden superior.
function sumar(a, b) {
return a + b;
}
function restar(a, b) {
return a - b;
}
function operar(a, b, operacion) {
return operacion(a, b);
}
console.log(operar(4, 2, sumar));
// 6
console.log(operar(4, 2, restar));
// 2operar no sabe qué hace operacion, y no le hace falta saberlo: recibe tres valores (a, b y una función) y se limita a llamar a esa función con los otros dos. El comportamiento completo de operar cambia según qué función se le pase, sin tocar ni una línea de su propio código: pasar sumar da 6, pasar restar con los mismos 4 y 2 da 2.
console.log(operar(4, 2, (a, b) => a * b));
// 8No hace falta declarar una función aparte y ponerle un nombre para pasarla como argumento: una arrow function puede escribirse directamente en el lugar donde operar espera recibirla, sin quedar guardada en ninguna variable. Es una de las razones por las que la forma corta de arrow function, ya vista en el post de variables y funciones, aparece tan seguido junto con funciones de orden superior.
El ejemplo crearSaludo del post anterior ya mostraba el otro lado: una función que, en vez de recibir otra función, devuelve una. crearMultiplicador sigue el mismo patrón, con un resultado distinto según el valor que reciba cada vez.
function crearMultiplicador(factor) {
return function (numero) {
return numero * factor;
};
}
const duplicar = crearMultiplicador(2);
const triplicar = crearMultiplicador(3);
console.log(duplicar(5));
// 10
console.log(triplicar(5));
// 15crearMultiplicador no calcula nada por sí sola: devuelve una función nueva, todavía sin ejecutar, con factor ya fijado adentro. duplicar y triplicar son dos funciones distintas, cada una devuelta por una llamada distinta a crearMultiplicador, cada una con su propio factor (2 y 3). Llamar a duplicar(5) no ejecuta crearMultiplicador de nuevo: ejecuta la función que ya quedó devuelta y guardada, con el factor que le tocó en esa llamada puntual.
Nada impide combinar las dos formas en la misma función: una función de orden superior también puede recibir una función y devolver otra, distinta, que use a la primera por dentro.
function registrar(funcion) {
return function (valor) {
console.log(`Entra: ${valor}`);
const resultado = funcion(valor);
console.log(`Sale: ${resultado}`);
return resultado;
};
}
const doble = (n) => n * 2;
const dobleRegistrado = registrar(doble);
dobleRegistrado(5);
// Entra: 5
// Sale: 10registrar recibe una función (doble) y devuelve una función nueva que hace más que la original: antes de llamar a funcion, imprime el valor que entra, y después imprime el resultado que sale. doble no cambió ni una línea; dobleRegistrado es una versión distinta, armada por fuera, sin tocar el código de doble. Envolver una función con comportamiento extra sin modificarla es una de las razones principales por las que las funciones de orden superior son tan comunes en JavaScript.
Una función de orden superior es una función que recibe otra función como argumento, que devuelve una función, o que hace las dos cosas. Tratar a las funciones como valores (pasarlas, guardarlas, devolverlas) permite separar qué se hace de cómo y cuándo se llama, sin duplicar código para cada variante.
El próximo post trata map, reduce y filter: los métodos que toman esta misma idea, recibir una función como argumento, y la llevan al caso de uso más común de todos.