Artículos de Tecnología > Front End

Higher Order Functions: ¿qué son?

Time Alura Latam
Time Alura Latam

En este artículo vamos a entender qué son y cómo utilizar las funciones de orden superior o "higher order functions".

Una función de orden superior es una función que recibe otra función como argumento, o una función que devuelve otra función.

Veamos en la práctica cómo sucede esto creando un sistema de inicio de sesión que autentica usuarios y devuelve un mensaje de éxito.

Funciones

Según la documentación de Mozilla, una función es un conjunto de instrucciones que ejecuta una tarea.

Por lo tanto, en primer lugar vamos a crear dos funciones responsables del inicio de sesión de dos personas.

El siguiente código muestra dos funciones para imprimir un mensaje en la consola después de que finalice la iteración del array. Esta iteración representa el periodo que el sistema tardaría en autenticar que los usuarios Luke y Leia han iniciado sesión correctamente:


const lukeLogin = () => {
    let array = []
    for( i = 0; i < 90000; i++){
        array.push(i)
    }
    return "¡Luke ha iniciado sesión correctamente!"
}

const leiaLogin = () => {
    let array = []
    for( i = 0; i < 90000; i++){
        array.push(i)
    }
    return "¡Leia ha iniciado sesión correctamente!"
}

lukeLogin()
leiaLogin()

Al ejecutar ambas funciones, obtendremos como resultado:

"¡Luke ha iniciado sesión correctamente!"
"¡Leia ha iniciado sesión correctamente!"

Podemos percibir que tenemos dos funciones realizando una misma tarea, que es iniciar sesión. Pensando en cómo podemos mejorar este código, surge de inmediato el concepto DRY, don’t repeat yourself o "no te repitas" en traducción literal.

Para resolver esta cuestión, vamos a reemplazar el código anterior por una sola función que manejará el inicio de sesión. Al ejecutarla, pasamos por parámetro el nombre de quien está iniciando sesión:

const usuarioLogin = (persona) => {
    let array = []
    for( i = 0; i < 90000; i++){
        array.push(i)
    }
    return ¡${persona} ha iniciado sesión correctamente en el sistema!
}

usuarioLogin("Luke")

Al ejecutar la función tendremos:

"¡Luke ha iniciado sesión correctamente en el sistema!"

Podemos mejorar aún más este código. Para ello, pensemos en el poder de la composición de funciones.

Retornando una función

Al refactorizar el primer código, todavía combinamos dos responsabilidades diferentes en el mismo código, ya que creamos una función que involucra la lógica de iniciar sesión a través del nombre del usuario y escribimos la forma de mostrar el resultado en la consola.

A través del concepto de función de orden superior, podemos componer funciones para separar tareas diferentes. Para ejemplificar, podemos crear una función de acceso que se encargará de la visualización del resultado y otra que se encargará de la lógica:


const acceso = (nombre) => {
    return ${nombre} ha iniciado sesión correctamente en el sistema!
}

const usuarioLogin = (nombre) => {
    let array = []
    for( i = 0; i < 90000; i++){
        array.push(i)
    }
    return acceso(nombre)
}

usuarioLogin("Luke")

Como las dos funciones están en el mismo ámbito global, la función usuarioLogin() puede acceder a la función acceso(). Por lo tanto, se generan funciones con diferentes responsabilidades dentro de otras funciones, y el valor devuelto por la función usuarioLogin() es otra función, acceso().

Esto es posible porque en JavaScript las funciones también son valores que se pueden asignar a variables y "pasar hacia adelante", algo que no todos los lenguajes de programación hacen.

En el caso de la función usuarioLogin(), recibimos un nombre como argumento. Pero como su responsabilidad es la lógica, podemos devolver dentro de ella la función acceso() que recibirá el nombre pasado en la función usuarioLogin(), ejecutará su lógica y mostrará el resultado en la pantalla.

Por lo tanto, hemos refactorizado nuestro inicio de sesión y hemos utilizado el concepto de funciones de orden superior para componer mejor nuestro sistema. Pero, ¿qué sucede si queremos agregar otro cargo, como el de directora, por ejemplo?

Recibiendo una función y devolviendo una función

Digamos que debido a su cargo, una directora tendría un tiempo de inicio de sesión mayor, lo cual sería posible incluyendo verificaciones en el sistema para aumentar este periodo. En ese caso, ¿tendríamos que duplicar nuestro código, verdad?

Entonces, vamos a crear una función para la directora:

const acceso = (nombre) => {
  return `${nombre} ha iniciado sesión correctamente en el sistema!`
}

const usuarioLogin = (nombre) => {
  let array = []
  for( i = 0; i < 90000; i++){
      array.push(i)
  }
  return acceso(nombre)
}

const juntaDirectivaLogin = (nombre) => {
  let array = []
  for( i = 0; i < 900000; i++){
      array.push(i)
  }
  return acceso(nombre)
}

directoraLogin("Leia")

En la pantalla se muestra:

"¡Leia ha iniciado sesión correctamente en el sistema!"

Pero imagina si tuviéramos que crear varios cargos, ¿tendríamos que repetir el código varias veces? No necesariamente. Una buena solución en esta situación sería crear una función genérica de autenticación:

const autenticar = (cargo) => {
  let array = []
  for( i = 0; i < cargo; i++){
    array.push(i)
  }
  return true;
}

Con esta función creada, podemos ampliar aún más la composición de funciones, ya que una función de orden superior puede tanto recibir una función como parámetro como devolver otra función.

Entonces, podemos refactorizar la función login() para que reciba y devuelva funciones:

const login = (persona, autenticar) => {
  if(persona.cargo === `funcionario`) {
     autenticar(90000)
  } else if(persona.cargo === `juntaDirectiva`) {
     autenticar(900000)
  }
 return acceso(persona.nombre)
}

El código completo se ve así:

const acceso = (nombre) => {
  return `${nombre} ha iniciado sesión correctamente en el sistema!`
}

const autenticar = (cargo) => {
  let array = []
  for( i = 0; i < cargo; i++){
    array.push(i)
  }
  return true;
}

const login = (persona, autenticar) => {
  if(persona.cargo === 'funcionario') {
     autenticar(90000)
  } else if(persona.cargo === 'juntaDirectiva') {
     autenticar(900000)
  }
 return acceso(persona.nombre)
}

Vamos a ver qué ocurre al ejecutar el código, pasando los parámetros esperados a la función login - un objeto con las propiedades cargo y nombre, y la función autenticar que se está pasando como valor:

login({cargo: `juntaDirectiva`, nombre: `Leia`}, autenticar)

La función de orden superior login compara el valor de la clave cargo en la estructura if...else y ejecuta la función autenticar pasando el valor 900000 como parámetro, ya que persona.cargo === 'juntaDirectiva'.

La función autenticar se ejecuta y se utiliza el valor 900000 en el bucle for. Una vez que comienza el bucle, JavaScript solo continúa ejecutando las demás líneas de la función después de que se completa la iteración.

Al finalizar el bucle, la función autenticar ejecuta su última línea y devuelve el valor true. Este valor se devuelve a la función login, que continúa su flujo normal hasta la última línea, donde llama a la función acceso pasando el valor de la clave nombre y recibe de vuelta el retorno de acceso, una cadena de texto que dice "¡Leia ha iniciado sesión correctamente en el sistema!".

Las funciones acceso y autenticar son "llamadas de vuelta" (o en inglés, "called back") por la función login; este tipo de función se conoce como "función de devolución de llamada" o "callback function", siendo la función login la función de orden superior en la jerarquía, es decir, la "higher order function".

Ahora, además de devolver una función, también estamos pasando otra función como argumento, la cual a su vez será llamada y recibirá sus propios argumentos basados en los datos que existen dentro de la función "superior" en términos de orden, es decir, en "higher order". Ese es el poder de las funciones de orden superior: permiten la composición de funciones y hacen que nuestro código sea más organizado y genérico para aceptar diversos tipos de interacciones.

Conclusión

Algunos de los métodos más modernos de arrays en JavaScript, como map(), forEach(), filter y reduce(), entre otros, utilizan el concepto de funciones de devolución de llamada (callback functions) en su sintaxis.

Felipe Nascimento

Desarrollador e instructor en Alura con un enfoque en JavaScript.

Artículos de Tecnología > Front End

En Alura encontrarás variados cursos sobre Front End. ¡Comienza ahora!

Semestral

  • 265 cursos

    Cursos de Programación, Front End, Data Science, Innovación y Gestión.

  • Videos y actividades 100% en Español
  • Certificado de participación
  • Estudia las 24 horas, los 7 días de la semana
  • Foro y comunidad exclusiva para resolver tus dudas
  • Luri powered by ChatGPT

    Luri es nuestra inteligencia artificial que resuelve dudas, da ejemplos prácticos y ayuda a profundizar aún más durante las clases. Puedes conversar con Luri hasta 100 mensajes por semana

  • Acceso a todo el contenido de la plataforma por 6 meses
US$65,90
un solo pago de US$65,90
¡QUIERO EMPEZAR A ESTUDIAR!

Paga en moneda local en los siguientes países

Anual

  • 265 cursos

    Cursos de Programación, Front End, Data Science, Innovación y Gestión.

  • Videos y actividades 100% en Español
  • Certificado de participación
  • Estudia las 24 horas, los 7 días de la semana
  • Foro y comunidad exclusiva para resolver tus dudas
  • Luri powered by ChatGPT

    Luri es nuestra inteligencia artificial que resuelve dudas, da ejemplos prácticos y ayuda a profundizar aún más durante las clases. Puedes conversar con Luri hasta 100 mensajes por semana

  • Acceso a todo el contenido de la plataforma por 12 meses
US$99,90
un solo pago de US$99,90
¡QUIERO EMPEZAR A ESTUDIAR!

Paga en moneda local en los siguientes países

Acceso a todos
los cursos

Estudia las 24 horas,
dónde y cuándo quieras

Nuevos cursos
cada semana