Funciones expresadas en JavaScript: ¿Qué son? Con ejemplos!

Las funciones expresadas en JavaScript son una forma versátil de definir funciones dentro del código, permitiendo flexibilidad en cómo y cuándo se ejecutan. Este artículo te muestra qué son, para qué sirven y cómo usarlas de forma efectiva, junto con ejemplos que ilustran su poder en distintos contextos. Descubre cuándo usar funciones expresadas para optimizar tu código y mejorar su legibilidad.

que son las funciones expresadas en javascript

1 ¿Qué son las funciones expresadas en JavaScript?

  1. ¿Qué significa que sea una «expresión de función»?
  2. Sintaxis de una función expresada:
  3. Ejemplo de una función expresada:
  4. Función expresada nombrada:

En JavaScript, una función expresada es una FUNCIÓN que se define al asignarla a una variable o constante.

A diferencia de las funciones declaradas, no se crea con el formato function nombre() { }, sino que se define directamente como una expresión y se le da un nombre solo si es necesario, pero normalmente se usa de forma anónima. Esto permite que la función sea almacenada en una variable o constante para ser utilizada más adelante.

ANALOGÍA:

Primero, debemos saber que es una función en JavaScript, una función es como una receta, te dice qué ingredientes necesitas y los pasos exactos para preparar un plato. En JavaScript, las funciones son bloques de código reutilizable que realizan una tarea específica.

Sabiendo esto, las funciones expresadas son como esas recetas que escribes directamente en una tarjeta y luego la pegas en la nevera. Pero en lugar de escribir la receta en un lugar especial (como un recetario), la estás «expresando» en un lugar específico de tu código.

1.1. ¿Qué significa que sea una «expresión de función»?

Una expresión de función ocurre cuando se crea una función como parte de una expresión. En JavaScript, una expresión es cualquier fragmento de código que produce un valor.

Así, al definir una función como expresión, no es obligatoria darle un nombre propio (aunque es opcionalmente posible). Este tipo de funciones se puede asignar a variables, ser utilizadas como argumentos en otras funciones, o incluso estar dentro de estructuras condicionales.

1.2. Sintaxis de una función expresada:

La sintaxis básica de una función expresada en JavaScript es la siguiente:

const nombreDeLaFuncion = function(parametro1, parametro2, ...) {
    // Código que se ejecuta en la función
    return resultado; // Opcional: Devuelve un valor
};Lenguaje del código: JavaScript (javascript)

NOTA!!!! Si te animas y deseas ver el resultado de este ejemplo y de todos los que iremos proporcionando directamente desde tu PC, te invito a seguir estos pasos.

  1. Primero, revisa el punto 5 del siguiente artículo sobre como usar e instalar VSCode (este es el editor de código mas usado), donde encontrarás los pasos para crear la estructura necesaria para visualizar una página desde tu navegador predeterminado.
  2. Si entendiste correctamente este paso anterior, sabrás donde colocar el código script que te acabamos de proporcionar (arriba). Ahora, puedes visualizar el resultado, para ello puedes hacer lo siguiente:
    • Una vez abierta y visualizada la página, abre la consola del navegador presionando la tecla F12.
    • Ahora, dirígete a la pestaña que dice Console, y desde aquí podrás ver el resultado del script que hayamos introducido anteriormente.
  3. No te preocupes, estos pasos son más simples de lo que parecen!!!! Entonces… cada vez que dejemos un código de ejemplo como éste, puedes seguir estos pasos y ver los resultados por ti mismo. ¡Ojalá te animes!!!!

Link para descargar el editor de código Visual Studi Code!!

Ahora si, veamos en detalle cada parte de la sintaxis:

  1. Asignación a una variable:
    • La función se asigna a una variable (en este caso, nombreDeLaFuncion). Esto convierte a la función en una expresión y permite llamarla usando el nombre de la variable.
  2. Palabra clave function:
    • La palabra clave function indica el inicio de la función. Aquí, se usa sin un nombre después de function ya que es una función anónima, pero también puedes darle un nombre si deseas, aunque no es común.
  3. Parámetros:
    • Dentro de los paréntesis ( ), puedes definir uno o más parámetros separados por comas, que representan los datos que la función puede recibir para procesar.
  4. Cuerpo de la función { }:
    • Entre llaves { }, se encuentra el bloque de código que se ejecutará cada vez que se llame a la función. Puedes incluir cualquier lógica, como cálculos, condicionales o loops.
  5. return:
    • El return es opcional, pero permite devolver un valor al lugar donde se llamó la función. Si no incluyes return, la función devolverá undefined por defecto.

1.3. Ejemplo de una función expresada:

Aquí tienes una función expresada que calcula el cuadrado de un número:

const cuadrado = function(num) {
    return num * num;
};

// Llamada a la función
console.log(cuadrado(4)); // Resultado: 16Lenguaje del código: JavaScript (javascript)

Explicación del ejemplo:

  • cuadrado es la variable const a la que se asigna la función expresada.
  • La función toma un parámetro num.
  • La función multiplica num por sí mismo (num * num) y devuelve el resultado.
  • Al llamar cuadrado(4), el valor 4 se pasa como argumento a num, y la función devuelve 16.

1.4. Función expresada nombrada:

Aunque no es común, puedes agregar un nombre a la función expresada.

Esto se hace así:

const saludo = function decirHola(nombre) {
    return `Hola, ${nombre}!`;
};

console.log(saludo("Manuel")); // Resultado: "Hola, Manuel!"Lenguaje del código: JavaScript (javascript)

En este caso, la función se llama decirHola, pero se invoca mediante saludo porque está asignada a esa variable. El nombre decirHola es útil para identificar la función en los errores, pero no se usa para llamar a la función.

2. ¿Cómo usar funciones expresadas en JavaScript? Paso a paso:

Aquí tienes un paso a paso detallado sobre cómo usar una función expresada en JavaScript.

  1. Paso 1: Definir la función expresada
  2. Paso 2: Llamar a la función usando el nombre de la variable
  3. Paso 3: Reutilizar la función

Paso 1: Definir la función expresada

Primero, defines la función expresada y la asignas a una variable. Aquí tienes un ejemplo básico:

const multiplica = function(a, b) {
    return a * b;
};Lenguaje del código: JavaScript (javascript)

Explicación de este paso:

  • const multiplica crea una constante llamada multiplica.
  • function(a, b) { return a * b; } es la función anónima que se asigna a multiplica.
  • La función recibe dos parámetros a y b, y retorna el producto de ambos (a * b).

Paso 2: Llamar a la función usando el nombre de la variable

Para usar la función, la llamas con el nombre de la variable (multiplica) y le pasas los valores (argumentos) que deseas procesar.

const resultado = multiplica(3, 4);
console.log(resultado); // Resultado: 12Lenguaje del código: JavaScript (javascript)

Explicación:

  • multiplica(3, 4) llama a la función y pasa 3 como valor de a y 4 como valor de b.
  • La función realiza la operación 3 * 4 y devuelve 12.
  • resultado almacena el valor devuelto por la función, que en este caso es 12.
  • console.log(resultado); imprime 12 en la consola.

Paso 3: Reutilizar la función

La función expresada multiplica se puede reutilizar con diferentes valores cada vez que la llamas:

console.log(multiplica(5, 5)); // Resultado: 25
console.log(multiplica(2, 8)); // Resultado: 16Lenguaje del código: JavaScript (javascript)

Explicación:

  • Llamamos a multiplica con diferentes argumentos, y la función ejecuta la operación con los nuevos valores.

Ejemplo completo

// PASO 1: Definir la función expresada
const multiplica = function(a, b) {
    return a * b;
};

// PASO  2: Llamar a la función y almacenar el resultado
const resultado1 = multiplica(3, 4);
console.log(resultado1); // Resultado: 12

// PASO  3: Reutilizar la función con diferentes valores
console.log(multiplica(5, 5)); // Resultado: 25
console.log(multiplica(2, 8)); // Resultado: 16Lenguaje del código: JavaScript (javascript)

RECUERDA!!!! Las funciones expresadas no pueden ser llamadas antes de ser definidas debido a que no se «elevan» (hoisting) como las declaraciones de funciones.

3. Características de las funciones expresadas en JavaScript.

Aquí profundizamos en cada una de las características clave de las funciones expresadas:

  1. Asignación a una variable:
  2. No se elevan (Hoisting)
  3. Anonimato de las funciones expresadas:

3.1, Asignación a una variable:

  1. Vinculación inseparable:
    • Una función expresada siempre está ligada a una variable. Esta variable actúa como un «alias» para la función, permitiendo que la llames en cualquier momento usando ese nombre.
  2. Reasignación:
    • Aunque una función expresada está asignada a una variable, puedes reasignar esa variable a otra función o valor en cualquier momento. Sin embargo, la función original no se modifica, solo la referencia a ella.
  3. Ejemplo:
const suma = function(a, b) {
  return a + b;
};

// Usando la función
let resultado = suma(5, 3); // resultado será 8Lenguaje del código: JavaScript (javascript)

Aquí:

  • Se crea una función expresada y se asigna a la constante suma. La función toma dos parámetros, a y b, y devuelve la suma de ambos (a + b).
  • Después, se llama a la función suma con los valores 5 y 3 como argumentos. La función suma estos valores y devuelve 8, que se asigna a la variable resultado.

3.2. No se elevan (Hoisting)

  1. Disponibilidad tardía:
    • A diferencia de las declaraciones de función, que están disponibles en todo el ámbito donde se declaran, las funciones expresadas solo están accesibles a partir de la línea donde se asigna la variable.
  2. Error de referencia:
    • Si intentas llamar a una función expresada antes de su declaración, obtendrás un error de «ReferenceError» porque la variable aún no ha sido definida.
  3. Ejemplo:
console.log(resta); // Error: resta is not defined
const resta = function(a, b) {
  return a - b;
};
Lenguaje del código: JavaScript (javascript)

Aquí:

  • Se intenta acceder a la función resta antes de que esté definida con console.log(resta);
  • Esto produce un error porque las funciones expresadas no son elevadas (no tienen hoisting).
  • La función resta se asigna a una constante después del console.log, por lo que cuando intenta acceder a resta, esta aún no está definida.

3.3. Anonimato de las funciones expresadas:

  • Funciones sin nombre: Las funciones expresadas no necesitan un nombre explícito. Pueden ser anónimas, lo cual es útil cuando:
    • Se usan una sola vez: Por ejemplo, como callbacks en eventos o como argumentos de otras funciones.
    • Se crean funciones dinámicamente: Puedes generar funciones sobre la marcha sin tener que darles un nombre específico.
  • Ejemplo:
// Función anónima como callback
let array = [1, 2, 3];
array.forEach(function(elemento) {
  console.log(elemento);
});
Lenguaje del código: PHP (php)

Aquí:

  • Se usa una función anónima expresada dentro de forEach para imprimir cada elemento del array, mostrando 1, 2 y 3 en la consola. La función no necesita nombre porque se usa solo dentro del contexto de forEach.

RESUMEN: Las funciones expresadas ofrecen una gran flexibilidad y son una herramienta esencial en el arsenal de cualquier desarrollador JavaScript. Al comprender estas características clave, podrás escribir código más limpio, eficiente y modular.

4. Asignación de funciones expresadas a constantes y variables.

Como ya dijimos, en JavaScript, puedes asignar funciones expresadas a variables declaradas con let, const, o var. Sin embargo, el tipo de declaración que elijas afecta el comportamiento de la función asignada de diferentes maneras, especialmente en términos de mutabilidad (si el valor puede cambiar) y alcance (scope).

4.1. Diferencias entre asignar funciones expresadas a let, const, o var:

  1. const:
    • Define una constante de bloque, es decir, el valor no puede ser reasignado.
    • La función asignada a const no se puede modificar, lo que significa que si intentas cambiar su referencia, se generará un error.
    • Tiene un scope de bloque (solo es accesible dentro del bloque en el que fue declarada).
  2. let:
    • Define una variable de bloque que puede reasignarse, pero solo dentro del bloque de código donde fue declarada.
    • La referencia de la función puede cambiarse (puedes asignar una nueva función o valor a la variable).
    • También tiene un scope de bloque.
  3. var:
    • Define una variable de función o global, dependiendo de dónde se declare.
    • La referencia de la función puede cambiarse, al igual que let.
    • Tiene un scope de función o global (se eleva al inicio del contexto de ejecución), por lo que puede usarse antes de su declaración en el código, aunque esto puede llevar a errores.

4.2. Ejemplos de funciones expresadas con const, let, y var.

Vamos a ver cómo se comportan las funciones expresadas cuando se asignan a const, let, y var, y cómo el tipo de declaración afecta la mutabilidad y el scope con estos ejemplos:

4.2.1. Asignación con const

Al usar const, asignas una función expresada a una constante. Esto significa que no podrás reasignar la referencia de la función a otro valor o función.

const saludar = function(nombre) {
  return `Hola, ${nombre}!`;
};

console.log(saludar("Ana")); // "Hola, Ana"

// INTENTO DE REASIGNACIÓN (causará un error)
saludar = function(nombre) {
  return `Buenos días, ${nombre}!`;
}; // Error: Assignment to constant variable.Lenguaje del código: JavaScript (javascript)

IMPORTANTE: Aunque const no permite la reasignación de la referencia, la propia función puede ejecutar cambios en datos internos (si está modificando un array, objeto, etc.). Sin embargo, la referencia de saludar no puede cambiarse a otra función o valor.

4.2.2. Asignación con let

Al usar let, puedes asignar una función expresada y reasignar su referencia después. Esto permite una mayor flexibilidad.

let despedir = function(nombre) {
  return `Adiós, ${nombre}!`;
};

console.log(despedir("Ana")); // "Adiós, Ana"

// REASIGNACIÓN de la función a una nueva referencia
despedir = function(nombre) {
  return `Hasta pronto, ${nombre}!`;
};

console.log(despedir("Ana")); // "Hasta pronto, Ana!"Lenguaje del código: JavaScript (javascript)

NOTA: let es útil cuando necesitas una función que puede redefinirse en base a condiciones o requerimientos en tu código. La función sigue teniendo scope de bloque, lo que significa que solo es accesible dentro del bloque en el que se define.

4.2.3. Asignación con var

Usar var para asignar una función expresada tiene un comportamiento único debido a su scope de función/global y hoisting. Aunque permite la reasignación de la referencia de la función, el hoisting puede causar comportamientos inesperados. (Actualmente, poco usado)

console.log(presentar("Ana")); // undefined: Esto causa un error de tipo porque `var presentar` se eleva como undefined

var presentar = function(nombre) {
  return `Hola, soy ${nombre}!`;
};

console.log(presentar("Ana")); // "Hola, soy Ana"

// Reasignación de la función a una nueva referencia
presentar = function(nombre) {
  return `Encantado de conocerte, ${nombre}!`;
};

console.log(presentar("Ana")); // "Encantado de conocerte, Ana!"Lenguaje del código: JavaScript (javascript)

NOTA: var eleva la declaración de presentar al inicio del scope, pero no su inicialización. Esto hace que presentar esté disponible antes de su declaración, pero con un valor de undefined. Para evitar errores, se recomienda evitar el uso de var para funciones expresadas y optar por const o let.

4.3. Resumen:

  • const: Ideal para funciones que no deben cambiar de referencia. No permite reasignación y tiene un scope de bloque.
  • let: Útil si planeas reasignar la función. Tiene un scope de bloque y permite flexibilidad en el cambio de referencia.
  • var: Permite reasignación, pero se recomienda evitarlo por el comportamiento de hoisting, que puede llevar a errores difíciles de detectar.

Este conocimiento te ayudará a seleccionar el tipo de declaración adecuado y a manejar tus funciones de forma profesional en JavaScript, controlando mejor su alcance y flexibilidad en el código.

5. El scope léxico en las funciones Expresadas.

¿Qué es el scope léxico?

El scope léxico (lexical scope) define cómo se resuelven las variables en JavaScript. Se basa en la ubicación física del código en el momento de la escritura, y no en el lugar donde se ejecuta. Esto significa que una función siempre «recordará» el contexto en el que fue creada, independientemente de dónde se invoque.

5.1. El scope léxico en funciones expresadas:

Cuando una función expresada se crea, hereda el scope del lugar donde fue definida. Esto significa que puede acceder a todas las variables disponibles en ese contexto, además de las variables definidas dentro de la propia función.

Ejemplo:

function crearFuncion() {
  let saludo = "Hola";

  const funcionExpresada = function(nombre) {
    return `${saludo}, ${nombre}!`;
  };

  return funcionExpresada;
}

const miFuncion = crearFuncion();
console.log(miFuncion("Ana")); // "Hola, Ana!"Lenguaje del código: JavaScript (javascript)

Explicación:

  • La variable const funcionExpresada recuerda el scope léxico donde fue definida (dentro de de la función crearFuncion).
  • Aunque crearFuncion termina su ejecución, funcionExpresada sigue teniendo acceso a saludo gracias al scope léxico.

5.1.1. Características del scope léxico

  1. Acceso a Variables Externas: Las funciones expresadas pueden acceder a variables definidas en su entorno externo, pero no al revés.
  2. Inmutabilidad del Scope: Una vez que una función captura su scope léxico, este no cambia aunque se invoque la función en un contexto diferente.

6. Diferencia entre función declarada y función expresada.

Las funciones declaradas y las expresadas son maneras diferentes de definir funciones en JavaScript, y cada una tiene características únicas que las hacen más adecuadas para ciertos contextos.

Vamos a desglosar las diferencias clave con ejemplos prácticos:

  1. Diferencias en la elevación (Hoisting):
  2. Diferencias de contexto de uso:
  3. Diferencias de legibilidad y control:
  4. Resumen de diferencias

6.1. Diferencias en la elevación (Hoisting):

La elevación es un comportamiento de JavaScript en el que las declaraciones de variables y funciones son «movedoras» al principio de su contexto (alcance o scope) durante la fase de compilación, antes de ejecutar el código.

6.1.1. La elevación en Funciones declaradas:

  • SI SE ELEVAN: Las funciones declaradas están disponibles para su uso incluso antes de que aparezcan en el código, porque su definición completa (código de la función) se eleva al comienzo del contexto.
  • Ejemplo:
// Llamar a la función antes de declararla
console.log(saludar("Juan")); // Salida: "Hola, Juan"

function saludar(nombre) {
  return `Hola, ${nombre}`;
}Lenguaje del código: JavaScript (javascript)

En este caso, la función saludar puede ser llamada antes de ser definida en el código porque es elevada.

6.1.1. La elevación en funciones expresadas:

  • NO SE ELEVAN: Las funciones expresadas no están disponibles antes de la línea en la que se definen. Si intentas llamarlas antes de su definición, obtendrás un error.
  • Ejemplo:
console.log(sumar(2, 3)); // Error: Cannot access 'sumar' before initialization

const sumar = function(a, b) {
  return a + b;
};Lenguaje del código: JavaScript (javascript)

Este código genera un error porque sumar no se eleva como una función declarada. El intérprete encuentra la variable sumar pero no puede ejecutarla hasta que llega a la línea donde está definida.

6.2. Diferencias de contexto de uso:

El contexto en el que se usan las funciones declaradas y expresadas también varía. Cada tipo tiene ventajas en escenarios específicos.

6.2.1. Funciones declaradas:

  • Útiles para funciones reutilizables: Como se elevan, son ideales para funciones que necesitas usar en múltiples lugares a lo largo del archivo.
  • Más sencillas de leer y entender: La estructura de una función declarada suele ser más fácil de seguir, especialmente para quienes están comenzando con JavaScript.

6.2.2. Funciones expresadas

  • Mayor control del momento de uso: Las funciones expresadas solo están disponibles a partir de su definición, lo cual es útil para evitar llamarlas accidentalmente antes de tiempo.
  • Perfectas para asignar a variables: Esto las hace ideales para:
    • Métodos en objetos.
    • Funciones de orden superior como map, filter o reduce.
    • Callbacks que solo se necesitan en un contexto específico.

6.3. Diferencias de legibilidad y control:

6.3.1. Funciones declaradas:

  • Más visibles: Su elevación y el hecho de que están disponibles globalmente dentro de su ámbito las hace prácticas para funciones principales.
  • Menos control del ámbito: Si no estás atento, pueden ser llamadas fuera del contexto previsto debido a la elevación.

6.3.2. Funciones expresadas:

  • Encapsulación: Como solo existen después de ser definidas, son perfectas para usar en módulos o cuando necesitas evitar que estén disponibles fuera de su contexto inmediato.
  • Flexibilidad: Puedes asignarlas dinámicamente a variables o constantes dependiendo de la lógica del programa.

6.4. Resumen de diferencias

CaracterísticaFunción DeclaradaFunción Expresada
ElevaciónSí, se puede llamar antes de definirlaNo, solo existe después de ser definida
Sintaxisfunction nombre() { ... }const nombre = function() { ... };
Contexto de UsoFunciones principales, reutilizablesMétodos de objetos, callbacks, closures
LegibilidadMás legible para funciones generalesMás controlada en su ámbito y contexto

7. Funciones expresadas y closures en JavaScript.

¿Que es un clouser? Un closure en JS ocurre cuando una función «recuerda» el contexto léxico en el que fue creada, incluso después de que dicho contexto haya terminado de ejecutarse. Esto permite que una función pueda acceder a las variables de su scope externo, aunque este ya no exista en el tiempo de ejecución.

7.1. ¿Porqué las funciones expresadas son útiles para trabajar con closures?:

Son especialmente útiles porque:

  • Pueden definirse dentro de otra función, capturando el estado de las variables de ese scope.
  • El closure permite encapsular lógica y datos, lo que es ideal para situaciones donde necesitamos persistir información.

Ejemplo:

function crearContador() {
  let contador = 0;

  const incrementar = function() {
    contador++;
    return contador;
  };

  return incrementar;
}

const miContador = crearContador();
console.log(miContador()); // 1
console.log(miContador()); // 2
console.log(miContador()); // 3Lenguaje del código: JavaScript (javascript)

Análisis:

  • La función crearContador define la variable contador en su scope.
  • La función expresada incrementar se crea dentro de crearContador y captura el estado de la variable contador.
  • Aunque crearContador termina su ejecución, el closure permite que al llamar a la función con miContador se siga accediendo a contador.

7.2. Características clave de closures con funciones expresadas:

  1. Persistencia de Estado:
    • Las variables definidas en el scope donde se creó la función no se destruyen, siempre que el closure tenga una referencia activa a ellas.
  2. Encapsulación de Datos:
    • Puedes usar closures para ocultar variables internas y exponer solo las funciones que las manipulan, creando así módulos pequeños y reutilizables.

Ejemplo de encapsulación:

function crearBanco() {
  let saldo = 100;

  return {
    depositar: function(cantidad) {
      saldo += cantidad;
      return `Saldo actual: ${saldo}`;
    },
    retirar: function(cantidad) {
      if (cantidad > saldo) {
        return "Fondos insuficientes";
      }
      saldo -= cantidad;
      return `Saldo actual: ${saldo}`;
    }
  };
}

const banco = crearBanco();
console.log(banco.depositar(50));  // "Saldo actual: 150"
console.log(banco.retirar(30));   // "Saldo actual: 120"
console.log(banco.saldo);        // undefinedLenguaje del código: JavaScript (javascript)

Aquí, se utiliza encapsulación de datos con closures para ocultar la variable saldo y exponer solo las funciones que permiten manipularla.

Aquí está la explicación paso a paso:

1- Definición de la función principal crearBanco:

  • Dentro de crearBanco, se declara una variable privada saldo inicializada en 100.
  • crearBanco retorna un objeto con dos métodos:
    • depositar: Incrementa el saldo.
    • retirar: Reduce el saldo, verificando que haya fondos suficientes.

2- Creación de un «banco» independiente con const banco = crearBanco();

  • Al ejecutar crearBanco(), se crea un nuevo entorno de ejecución.
  • En este entorno, la variable saldo y las funciones depositar y retirar quedan encapsuladas.
  • El objeto retornado expone solo los métodos depositar y retirar, que acceden al saldo privado mediante un closure.

3- Uso del closure para operar con el saldo:

  • Al llamar a la función, banco.depositar(50) accede al closure, suma 50 al saldo y devuelve el nuevo saldo.
  • Mientras que banco.retirar(30) accede al closure, verifica si hay fondos suficientes, resta 30 del saldo y devuelve el saldo actualizado.

4- Encapsulación de la variable saldo:

  • La variable saldo no es accesible directamente desde fuera de crearBanco.
  • Al intentar acceder a banco.saldo devuelve undefined, porque saldo no forma parte del objeto retornado; está encerrada dentro del closure.

5- Resumen del ejemplo con encapsulación de datos:

  • Este código utiliza closures para crear un «módulo» de un banco con un saldo privado. Las operaciones de depósito y retiro están encapsuladas, proporcionando un acceso controlado al saldo mediante los métodos depositar y retirar, mientras que la variable saldo permanece inaccesible desde el exterior.

8. Funciones expresadas como callbacks en métodos de arrays.

Las funciones expresadas como callbacks son una herramienta esencial para trabajar con arrays en JavaScript. Permiten una manipulación de datos flexible y eficiente, y son la base de muchos patrones de programación funcional.

¿Qué son los callbacks en métodos de arrays? Un callback es una función que se pasa como argumento a otra función. En el contexto de los métodos de arrays en JavaScript, los callbacks permiten realizar operaciones personalizadas sobre cada elemento de un array.

Veamos algunos ejemplos donde los métodos como map, filter, y forEach esperan funciones expresadas como callback para realizar operaciones personalizadas en cada elemento de un array:

8.1. Ejemplo de función expresadas con map: Transformar un array

El método map crea un nuevo array aplicando una función a cada elemento del array original.

Ejemplo:

const numeros = [1, 2, 3, 4, 5];

const dobles = numeros.map(function(numero) {
  return numero * 2;
});

console.log(dobles); // [2, 4, 6, 8, 10]Lenguaje del código: JavaScript (javascript)

Aquí, se usa una función expresada anónima dentro del método map. Mientras que map se usa para crear un nuevo array llamado dobles, donde cada elemento del array numeros es multiplicado por 2. Esto no afecta el array original y devuelve un nuevo conjunto de valores transformados.

8.2. Ejemplo de función expresadas con filter: Filtrar elementos

El método filter devuelve un nuevo array con los elementos que cumplan una condición especificada en el callback.

Ejemplo:

const numeros = [1, 2, 3, 4, 5, 6];

const pares = numeros.filter(function(numero) {
  return numero % 2 === 0; // Solo números pares
});

console.log(pares); // [2, 4, 6]Lenguaje del código: JavaScript (javascript)

Aquí, la función anónima expresada está definida en línea como argumento del método filter. Esta función encapsula la lógica para determinar si un número es par (numero % 2 === 0). Creando un nuevo array con los números que cumplen la condición.

8.3. Ejemplo de función expresadas con forEach: Iterar sobre elementos:

El método forEach ejecuta un callback para cada elemento del array, pero no crea un nuevo array.

Ejemplo:

const frutas = ["manzana", "banana", "pera"];

frutas.forEach(function(fruta, index) {
  console.log(`Fruta ${index + 1}: ${fruta}`);
});

// Fruta 1: manzana
// Fruta 2: banana
// Fruta 3: peraLenguaje del código: JavaScript (javascript)

Aquí, utiliza una función expresada anónima con forEach para recorrer un array y ejecutar una operación específica en cada elemento: mostrar su índice (ajustado para empezar en 1) y su valor. Esto encapsula la lógica directamente donde se necesita, haciendo el código legible y eficiente.

9. Funciones expresadas dentro de objetos en JavaScript.

Las funciones expresadas son herramientas poderosas para crear métodos dentro de objetos en JavaScript. Este enfoque permite organizar el código y asociar funcionalidades directamente con los datos.

9.1. Ejemplo de una función expresada dentro de objetos:

Cuando asignamos una función a una propiedad de un objeto, estamos esencialmente creando un método. Este método puede luego ser llamado en cualquier momento utilizando la notación de punto.

Las funciones expresadas son perfectas para este propósito, ya que nos permiten definir funciones directamente en el lugar donde se necesitan.

Veamos el ejemplo:

const calculadora = {
  sumar: function(a, b) {
    return a + b;
  },
  restar: function(a, b) {
    return a - b;
  }
};

console.log(calculadora.sumar(3, 5)); // 8
console.log(calculadora.restar(10, 4)); // 6Lenguaje del código: JavaScript (javascript)

Aquí, se define un objeto llamado calculadora, el cual tiene dos propiedades (sumar y restar) que son funciones expresadas. Estas funciones se comportan como métodos del objeto, ya que pueden ejecutarse utilizando la notación de punto (calculadora.sumar() o calculadora.restar()).

10. Funciones expresadas y recursividad en JavaScript.

¿Qué es la recursividad? La recursión en JS es una técnica en la que una función se llama a sí misma para resolver un problema más grande dividiéndolo en subproblemas más pequeños.

Las funciones expresadas también pueden ser utilizadas para implementar recursión, aunque presentan algunas particularidades importantes que debes entender.

10.1. ¿Cómo usar una función expresada para la recursión?:

Una función expresada, al ser asignada a una variable o constante, puede llamarse a sí misma a través del nombre de dicha variable o constante. Este comportamiento es similar al de las funciones declaradas, pero con algunas diferencias en cuanto a cómo se manejan los nombres internos.

Ejemplo básico de recursión:

Calcular el factorial de un número:

const factorial = function(n) {
  if (n <= 1) return 1;
  return n * factorial(n - 1);
};

console.log(factorial(5)); // 120Lenguaje del código: JavaScript (javascript)

Aquí, la función factorial se llama a sí misma mediante la referencia de la variable a la que está asignada.

10.2. Consideraciones a tener en cuenta en la recursividad con funciones expresadas:

10.2.1. Problemas con el nombre de la variable:

En una función expresada, el nombre de la variable que contiene la función es crucial para permitir la recursión. Si la referencia a la función cambia, la recursión podría romperse.

Ejemplo:

const original = function(n) {
  if (n <= 1) return 1;
  return n * original(n - 1);
};

const alias = original; // Creamos un alias
original = null; // Perdemos la referencia original

console.log(alias(5)); // Error: original no es una funciónLenguaje del código: JavaScript (javascript)

En este ejemplo, la recursión falla porque la referencia a la función original se pierde.

10.2.2. Uso de nombres internos para llamadas recursivas:

Las funciones expresadas pueden definirse con un nombre interno que permite que la función se llame a sí misma, incluso si se pierde la referencia original.

Ejemplo con nombre interno:

const factorial = function innerFactorial(n) {
  if (n <= 1) return 1;
  return n * innerFactorial(n - 1); // Usamos el nombre interno
};

const alias = factorial;
factorial = null; // Eliminamos la referencia externa

console.log(alias(5)); // 120Lenguaje del código: JavaScript (javascript)

Aquí, el nombre interno innerFactorial asegura que la recursión funcione independientemente del nombre de la variable externa.

10.3. Ventajas y desventajas de usar recursión:

Ventajas:

  1. Simplicidad para problemas complejos: La recursión puede hacer que el código sea más fácil de leer para problemas como árboles, grafos o divisiones repetitivas.
  2. Modularidad: Divide el problema en subproblemas más pequeños de manera natural.

Desventajas:

  1. Coste de memoria: Cada llamada recursiva agrega un nuevo marco en la pila de llamadas, lo que puede causar un desbordamiento de pila si hay demasiadas llamadas.
  2. Ineficiencia en ciertos casos: Algunos problemas recursivos (como Fibonacci) pueden ser ineficientes sin optimización (como memoización).

10.4. Conclusión:

La recursión es una técnica esencial que puedes dominar con práctica. Al usar funciones expresadas para implementar recursión, asegúrate de comprender las diferencias entre nombres externos e internos, y aprende a optimizar tus soluciones para problemas más grandes y complejos.

11. Optimización de rendimiento con funciones expresadas.

El rendimiento en JavaScript puede verse afectado dependiendo de cómo y dónde se usan las funciones expresadas. Optimizar su implementación implica entender cómo se comportan en el scope, cómo manejan la asignación de memoria y cómo minimizar el impacto negativo de closures innecesarios.

11.1. Problema de scope y asignación en memoria:

El uso de funciones expresadas dentro de bucles o contextos repetitivos puede generar problemas de rendimiento debido a la asignación continua de memoria.

11.1.1. Problema: Creación repetitiva de funciones expresadas:

Cada vez que se ejecuta un bucle, una nueva instancia de la función es creada en memoria si la función expresada está definida dentro del bucle.

Ejemplo ineficiente:

for (let i = 0; i < 1000000; i++) {
  const procesar = function(valor) {
    return valor * 2;
  };
  procesar(i);
}Lenguaje del código: JavaScript (javascript)

Aquí, la función procesar se crea un millón de veces, lo que aumenta el consumo de memoria y el tiempo de ejecución.

11.1.2. Solución: Definir la función fuera del bucle:

Define la función expresada fuera del bucle para que se reutilice en lugar de crearse múltiples instancias.

Ejemplo optimizado:

const procesar = function(valor) {
  return valor * 2;
};

for (let i = 0; i < 1000000; i++) {
  procesar(i);
}Lenguaje del código: JavaScript (javascript)

Este enfoque garantiza que la función procesar se crea una vez y se reutiliza, reduciendo el impacto en la memoria.

11.2. Optimización de closures:

Los closures son útiles, pero su uso indiscriminado puede provocar retención innecesaria de memoria. Esto ocurre cuando los closures mantienen referencias a variables que ya no son necesarias.

11.2.1. Problema: Retención de variables innecesarias:

Los closures mantienen en memoria las variables del scope donde fueron creados, incluso si esas variables no se utilizan más.

Ejemplo ineficiente:

function crearFunciones() {
  let mensaje = "Hola, mundo!";
  return function() {
    console.log(mensaje);
  };
}

const funcion = crearFunciones();
// Aquí, el closure mantiene la referencia a `mensaje`, aunque no se necesite más.Lenguaje del código: JavaScript (javascript)

Este cierre innecesario puede generar fugas de memoria en aplicaciones más grandes.

11.2.2. Solución: Evita capturas innecesarias:

Refactoriza los closures para que capturen únicamente las variables que realmente necesitan.

Ejemplo Optimizado:

function crearFunciones() {
  const mensaje = "Hola, mundo!";
  return function() {
    console.log("Mensaje fijo");
  };
}

const funcion = crearFunciones();
// Aquí no se retiene el mensaje original, ya que no es necesario para la función.Lenguaje del código: JavaScript (javascript)

11.3. Otras estrategias de optimización:

11.3.1. Uso de funciones declaradas:

Cuando sea posible, utiliza funciones declaradas en lugar de funciones expresadas dentro de bucles o contextos de alta repetición. Las funciones declaradas son elevadas al inicio del scope, lo que puede mejorar el rendimiento al evitar redefinirlas constantemente.

11.3.2. Reutilización de funciones expresadas:

Cuando trabajes con eventos o iteraciones frecuentes, asigna funciones expresadas a variables estáticas para reutilizarlas.

11.3.3. Minimiza el uso de closures:

Limita los closures a situaciones donde sean absolutamente necesarios, como en patrones de diseño específicos o en implementaciones de privacidad.

11.4. Resumen:

  • Define fuera de bucles: Mueve las funciones expresadas fuera de contextos repetitivos para mejorar la reutilización y el consumo de memoria.
  • Evita closures innecesarios: Captura solo las variables imprescindibles para reducir la retención de memoria.
  • Usa herramientas de debugging: Identifica y soluciona problemas de rendimiento con herramientas como Chrome DevTools.
  • Piensa en escala: Optimiza tus funciones expresadas para escenarios de uso intensivo.

12. Usos comunes de funciones expresadas en el desarrollo web con JS.

  1. Manejo de Eventos en el DOM
    • Las funciones expresadas se usan frecuentemente para asignar controladores de eventos a elementos en la página, como hacer clic en botones, desplazarse por el sitio o cambios en los formularios.
  2. Callbacks Asíncronos
    • En el manejo de respuestas de solicitudes asíncronas, como las realizadas con fetch o XMLHttpRequest, las funciones expresadas se pasan como callbacks para procesar los resultados cuando la operación se complete.
  3. Métodos de Arrays
    • Las funciones expresadas se utilizan en métodos de array como map, filter, reduce o forEach para iterar sobre colecciones de datos y realizar transformaciones o filtrados.
  4. Definición de Funciones Anónimas
    • En situaciones donde no es necesario asignar un nombre a la función, como en la ejecución de operaciones rápidas, se usan funciones expresadas anónimas para realizar tareas inmediatas.
  5. Funciones de Temporización
    • En el uso de setTimeout y setInterval, las funciones expresadas permiten ejecutar código después de un intervalo de tiempo o de forma repetitiva, lo que es útil en animaciones o actualizaciones periódicas en la interfaz.
  6. Manipulación de Formatos de Entrada
    • Al trabajar con formularios en la web, las funciones expresadas se pueden usar para validar entradas de usuario o procesar los datos de manera rápida antes de enviarlos al servidor.
  7. Desestructuración y Operaciones con Objetos
    • En la manipulación de objetos y arrays complejos, las funciones expresadas se usan para desestructurar y acceder a valores específicos sin necesidad de declarar funciones completas.
  8. Interacción con APIs
    • Al interactuar con APIs externas, las funciones expresadas se utilizan para manejar las respuestas, procesar los datos o manejar errores, especialmente en entornos asíncronos.
  9. Gestión de Estados en Frameworks
    • En frameworks como React, las funciones expresadas son muy comunes para manejar cambios en el estado de los componentes, especialmente en los eventos de interacción con el usuario o la actualización de la interfaz.
  10. Animaciones y Efectos Dinámicos
    • Las funciones expresadas se emplean en la creación de animaciones y efectos interactivos con bibliotecas como GSAP o jQuery, permitiendo una rápida manipulación de la interfaz de usuario.
  11. Interacciones con la Historia del Navegador
    • Al usar la API de Historia del navegador, las funciones expresadas son útiles para manejar las interacciones con la URL sin recargar la página, permitiendo una navegación dinámica.
  12. Validación en Tiempo Real
    • Las funciones expresadas también se usan para validar formularios en tiempo real, mostrando mensajes de error o realizando modificaciones en la UI según los valores ingresados.

Estos son solo algunos de los muchos casos donde las funciones expresadas en JavaScript son una herramienta poderosa en el desarrollo web, debido a su flexibilidad, especialmente para trabajar con eventos, operaciones asíncronas y manipulación de datos.

12.1. Ejemplo real usando funciones expresadas con JavaScript.

Veamos un ejemplo real donde de (Manejo de eventos en el DOM). Para ello:

HTML: Supongamos que en un página web tenemos el siguiente HTML:

 <h5>MANEJO DE EVENTOS CON FUNCIONES EXPRESADAS</h5>
  <button id="alertButton">Mostrar Alerta</button>
  <button id="changeTextButton">Cambiar Texto</button>
  <p id="textParagraph">Este es un párrafo que cambiará.</p>Lenguaje del código: HTML, XML (xml)

JavaScript:

 // Función expresada para mostrar una alerta
    const showAlert = function () {
      alert("¡Has hecho clic en el botón de alerta!");
    };

    // Función expresada para cambiar el texto de un párrafo
    const changeText = function () {
      const paragraph = document.getElementById("textParagraph");
      paragraph.textContent = "¡El texto ha sido cambiado!";
    };

    // Asignación de eventos a los botones
    const alertButton = document.getElementById("alertButton");
    const changeTextButton = document.getElementById("changeTextButton");

    alertButton.addEventListener("click", showAlert);
    changeTextButton.addEventListener("click", changeText);Lenguaje del código: JavaScript (javascript)

RESULTADO del ejemplo:

Manejo de Eventos con Funciones Expresadas

Este es un párrafo que cambiará.

EXPLICACIÓN del ejemplo:

Aquí, utilizamos funciones expresadas para manejar eventos en el DOM. Aquí tienes una explicación:

  1. Definición de funciones expresadas:
    • Se crean dos funciones expresadas:
      • showAlert: Muestra una alerta con un mensaje cuando se ejecuta.
      • changeText: Cambia el texto de un párrafo a "¡El texto ha sido cambiado!".
  2. Uso de las funciones expresadas:
    • Ambas funciones se asignan como manejadores de eventos a botones específicos mediante addEventListener.
      • showAlert se ejecuta cuando haces clic en el botón «Mostrar Alerta».
      • changeText se ejecuta cuando haces clic en el botón «Cambiar Texto».
  3. Ventaja:
    • Las funciones expresadas permiten encapsular la lógica de cada acción, haciéndolas reutilizables y fáciles de asignar a múltiples eventos si fuera necesario.

En resumen, estas funciones expresadas se usan como manejadores de eventos para responder a clics en los botones.

13. Preguntas frecuentes y resumen sobre funciones expresadas en JS.

Las funciones expresadas se asignan a variables y no tienen hoisting, mientras que las declaradas pueden usarse antes de su definición en el código.

Se define asignando una función a una variable: const suma = function(a, b) { return a + b; }; Puede ser anónima o nombrada.

Las funciones declaradas se elevan al inicio del código, permitiendo su uso antes de su definición, mientras que las expresadas solo existen después de su asignación.

Se asigna usando const o let: const saludar = function() { console.log("Hola"); }; Luego se llama con saludar();.

Sí, una función expresada puede ser anónima: const multiplicar = function(a, b) { return a * b; };, sin necesidad de un nombre propio.

Se pasan como callbacks: function operar(fn, a, b) { return fn(a, b); } operar((x, y) => x + y, 5, 3);.

Se usan como argumentos en otras funciones: setTimeout(function() { console.log("Tiempo cumplido"); }, 1000);.

Se encapsulan en paréntesis: (function() { console.log("Autoejecutada"); })(); para ejecutarse inmediatamente.

Ventajas: encapsulación y flexibilidad. Desventajas: no tienen hoisting y pueden dificultar la depuración si son anónimas.

Se usan en patrones como módulo o fábrica: const contador = (function() { let c = 0; return () => ++c; })();.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *