Funciones de orden superior en JavaScript | Nicolás Garzón
Una función de orden superior es una función que recibe otra función, devuelve otra función o hace ambas cosas.
JavaScript
Copiar function applyOperation ( value, operation ) {
return operation ( value) ;
}
applyOperation ( 5 , ( number ) => number * 2 ) ; JavaScript
Copiar function filterProducts ( products, predicate ) {
const result = [ ] ;
for ( const product of products) {
if ( predicate ( product) ) {
result. push ( product) ;
}
}
return result;
} La función controla el recorrido. El callback define la condición.
JavaScript
Copiar const availableProducts = filterProducts (
products,
( product ) => product. stock > 0 ,
) ; Esto separa una estructura estable de una decisión variable.
JavaScript
Copiar function createMultiplier ( multiplier ) {
return function multiply ( value ) {
return value * multiplier;
} ;
}
const double = createMultiplier ( 2 ) ;
const triple = createMultiplier ( 3 ) ;
console. log ( double ( 5 ) ) ;
console. log ( triple ( 5 ) ) ; La función exterior configura un comportamiento. La función retornada lo utiliza después.
JavaScript
Copiar function wrapOperation ( operation ) {
return function wrappedOperation ( ... args) {
console. log ( "Before" ) ;
const result = operation ( ... args) ;
console. log ( "After" ) ;
return result;
} ;
}
const loggedSum = wrapOperation ( ( a, b ) => a + b) ;
loggedSum ( 2 , 3 ) ; wrapOperation recibe una función y devuelve otra que añade comportamiento.
Métodos como map, filter, find, some, every, reduce y sort son funciones de orden superior porque reciben callbacks.
JavaScript
Copiar const summaries = products
. filter ( ( product ) => product. isActive)
. map ( ( product ) => ( {
id : product. id,
name : product. name,
} ) ) ; Cada callback expresa una operación concreta y el método controla el recorrido.
JavaScript
Copiar function measureTime ( operation ) {
return function measuredOperation ( ... args) {
const start = performance. now ( ) ;
const result = operation ( ... args) ;
const end = performance. now ( ) ;
console. log ( ` ${ operation. name} took ${ end - start} ms ` ) ;
return result;
} ;
} JavaScript
Copiar const measuredCalculation = measureTime ( calculateReport) ;
measuredCalculation ( data) ; El wrapper añade medición sin modificar la implementación original.
Este tipo de función también puede añadir:
Logging.
Caché.
Validación.
Autorización.
Reintentos.
Transformación de resultados.
Un wrapper debe respetar el contrato de la función original.
JavaScript
Copiar function withLogging ( operation ) {
return function loggedOperation ( ... args) {
console. log ( "Arguments:" , args) ;
const result = operation ( ... args) ;
console. log ( "Result:" , result) ;
return result;
} ;
} Olvidar return result cambiaría el resultado a undefined.
Para funciones asíncronas, el wrapper debe manejar promesas según su contrato.
JavaScript
Copiar function withAsyncLogging ( operation ) {
return async function loggedOperation ( ... args) {
console. log ( "Started" ) ;
try {
const result = await operation ( ... args) ;
console. log ( "Completed" ) ;
return result;
} catch ( error) {
console. error ( "Failed" , error) ;
throw error;
}
} ;
} Una función puede fijar parte de la información y devolver otra función para completar el resto.
JavaScript
Copiar function createTaxCalculator ( taxRate ) {
return function calculateTax ( subtotal ) {
return subtotal * taxRate;
} ;
}
const calculateColombianTax = createTaxCalculator ( 0.19 ) ;
calculateColombianTax ( 100 ) ; Esto se relaciona con aplicación parcial : preparar una función con algunos datos conocidos.
Currying transforma conceptualmente una función con varios parámetros en una secuencia de funciones de un parámetro.
JavaScript
Copiar const multiply = ( first ) => ( second ) => first * second;
const double = multiply ( 2 ) ;
double ( 5 ) ; No es necesario escribir todo el código de esta forma. Es una herramienta útil en APIs funcionales y composición, pero puede reducir legibilidad si se aplica sin necesidad.
Componer significa conectar funciones para que el resultado de una sea la entrada de la siguiente.
JavaScript
Copiar const trim = ( value ) => value. trim ( ) ;
const toLowerCase = ( value ) => value. toLowerCase ( ) ;
const removeSpaces = ( value ) => value. replaceAll ( " " , "-" ) ;
const createSlug = ( value ) =>
removeSpaces ( toLowerCase ( trim ( value) ) ) ; Una utilidad de composición puede generalizar el flujo.
JavaScript
Copiar function pipe ( ... operations) {
return function process ( initialValue ) {
return operations. reduce (
( value, operation ) => operation ( value) ,
initialValue,
) ;
} ;
}
const createSlug = pipe ( trim, toLowerCase, removeSpaces) ; pipe ejecuta de izquierda a derecha, siguiendo el orden de lectura.
JavaScript
Copiar function retry ( operation, shouldRetry, maxAttempts = 3 ) {
return async function retriedOperation ( ... args) {
let attempt = 0 ;
while ( attempt < maxAttempts) {
try {
return await operation ( ... args) ;
} catch ( error) {
attempt++ ;
if ( attempt >= maxAttempts || ! shouldRetry ( error) ) {
throw error;
}
}
}
} ;
}
retry define el mecanismo.
operation representa el trabajo.
shouldRetry define la política de reintento.
Las funciones de orden superior permiten intercambiar decisiones sin duplicar el mecanismo.
Este código directo puede ser suficiente:
JavaScript
Copiar const activeProducts = products. filter (
( product ) => product. isActive,
) ; Crear varias capas genéricas para una operación usada una sola vez puede dificultar más de lo que ayuda.
Una abstracción aporta valor cuando:
El patrón se repite.
La variación puede expresarse con una función.
El nombre mejora la comprensión.
El contrato sigue siendo claro.
Cada llamada puede crear una función nueva.
JavaScript
Copiar const first = createMultiplier ( 2 ) ;
const second = createMultiplier ( 2 ) ;
console. log ( first === second) ; Esto importa en listeners, cachés y sistemas que comparan referencias.
JavaScript
Copiar function requirePermission ( permission, operation ) {
return function authorizedOperation ( user, ... args ) {
if ( ! user. permissions. includes ( permission) ) {
throw new Error ( ` Missing permission: ${ permission} ` ) ;
}
return operation ( user, ... args) ;
} ;
}
const deleteProduct = requirePermission (
"products:delete" ,
( user, productId ) => productRepository. remove ( productId) ,
) ; La función de orden superior añade una regla común y conserva la operación específica separada.
Creer que una función de orden superior tiene que ser asíncrona.
Confundir callback con función de orden superior: el callback es recibido; la función receptora es la de orden superior.
Crear wrappers que olvidan devolver el resultado.
Perder errores al envolver funciones asíncronas.
Crear una nueva función en cada llamada sin considerar identidad.
Aplicar currying o composición donde una función directa sería más clara.
Construir abstracciones genéricas antes de encontrar un patrón real.
Ocultar demasiadas responsabilidades dentro de un wrapper.
Una función de orden superior recibe o devuelve funciones.
Los métodos de arrays son ejemplos cotidianos.
Los wrappers añaden comportamiento alrededor de otra función.
La aplicación parcial fija parte de la configuración.
Currying y composición son herramientas, no obligaciones.
Separar mecanismo y política reduce duplicación.
Un wrapper debe respetar retornos, errores y asincronía.
Cada función retornada tiene su propia identidad.
¿Cuál es la función de orden superior y cuál es el callback?
JavaScript
Copiar function execute ( value, operation ) {
return operation ( value) ;
}
execute ( 5 , ( number ) => number * 2 ) ; Respuesta execute es la función de orden superior porque recibe una función. La arrow (number) => number * 2 es el callback.
Closures explica por qué una función retornada o almacenada puede seguir accediendo a los bindings del lugar donde fue creada.