En esta página

Funciones modernas

15 min lectura TextoCap. 1 — Fundamentos

Arrow functions

Las arrow functions (funciones flecha) son la forma más concisa de escribir funciones en JavaScript moderno. Introducidas en ES6, tienen reglas especiales:

  • No tienen su propio this (heredan del scope padre)
  • No tienen arguments (usa rest parameters en su lugar)
  • No se pueden usar como constructores (new)

Sintaxis concisa vs bloque

// Return implícito (una expresión)
const cuadrado = x => x * x;

// Return implícito de objeto (necesita parentesis)
const crearPunto = (x, y) => ({ x, y });

// Bloque con return explícito
const calcular = (a, b) => {
  const resultado = a + b;
  return resultado;
};

Parametros por defecto

Los parametros con valores por defecto evitan verificaciones manuales de undefined:

// Antes de ES6
function viejo(nombre) {
  nombre = nombre || 'Anonimo';
}

// ES6+
function moderno(nombre = 'Anonimo') {
  // nombre ya tiene valor por defecto
}

Rest parameters

El operador rest (...) captura un número variable de argumentos en un array real (a diferencia del viejo arguments):

function mayor(...números) {
  return Math.max(...números);
}
mayor(3, 7, 2, 9); // 9

Closures

Un closure es una función que recuerda las variables del scope donde fue creada, incluso cuando se ejecuta fuera de ese scope. Es uno de los conceptos más poderosos de JavaScript:

  • Permiten crear estado privado
  • Son la base de patrones como factory functions y módulos
  • Cada closure tiene su propia copia de las variables capturadas

Funciones de orden superior

Una función de orden superior es aquella que recibe funciones como argumentos o retorna funciones. Son fundamentales en programación funcional:

Patron Ejemplo Uso
Callback setTimeout(fn, 1000) Ejecución diferida
Factory crearValidador(min, max) Generador de funciones
Composicion componer(f, g) Combinar transformaciones

IIFE

Una IIFE (Immediately Invoked Function Expression) se ejecuta inmediatamente al definirse. Es útil para crear un scope aislado:

const api = (() => {
  let estado = 'listo';
  return {
    obtenerEstado: () => estado,
    ejecutar: () => { estado = 'ejecutando'; },
  };
})();

Práctica

  1. Crea una arrow function con parametros por defecto: Escribe una funcion calcularPrecioFinal que reciba precio y descuento = 0 y retorne el precio con el descuento aplicado. Probala con y sin el segundo argumento.
  2. Implementa un closure contador: Crea una funcion crearContador que retorne una funcion. Cada vez que se llame a la funcion retornada, debe incrementar y retornar un contador interno. Verifica que dos contadores creados por separado son independientes.
  3. Construye una factory function: Escribe una funcion crearMultiplicador(factor) que retorne otra funcion que multiplique cualquier numero por factor. Crea doble y triple a partir de ella y pruebalas.

En la siguiente leccion exploraremos objetos y arrays en profundidad.

Arrow functions y this
Las arrow functions no tienen su propio this. Heredan el this del scope donde fueron creadas. Esto las hace ideales para callbacks, pero no para métodos de objetos que necesitan acceder a this.
Funciones puras
Una función pura siempre retorna el mismo resultado para los mismos argumentos y no tiene efectos secundarios. Preferir funciones puras hace tu código más predecible y fácil de testear.
javascript
// Arrow functions
const sumar = (a, b) => a + b;
const saludar = nombre => `Hola, ${nombre}!`;

// Arrow con cuerpo
const calcularImpuesto = (precio, tasa = 0.13) => {
  const impuesto = precio * tasa;
  return precio + impuesto;
};

// Parametros por defecto
function crearUsuario(nombre, rol = 'estudiante', activo = true) {
  return { nombre, rol, activo };
}

// Rest parameters
function registrarLog(nivel, ...mensajes) {
  mensajes.forEach(msg => {
    console.log(`[${nivel}] ${msg}`);
  });
}
registrarLog('INFO', 'Servidor iniciado', 'Puerto 3000');

// Closures
function crearSaludo(prefijo) {
  return (nombre) => `${prefijo}, ${nombre}!`;
}
const hola = crearSaludo('Hola');
const buenas = crearSaludo('Buenos dias');
console.log(hola('Carlos'));      // "Hola, Carlos!"
console.log(buenas('Maria'));     // "Buenos dias, Maria!"

// IIFE (Immediately Invoked Function Expression)
const config = (() => {
  const env = 'producción';
  return { env, debug: env !== 'producción' };
})();
javascript
// Funciones de orden superior
function repetir(n, accion) {
  for (let i = 0; i < n; i++) {
    accion(i);
  }
}
repetir(3, i => console.log(`Iteracion ${i}`));

// Retornar funciones (factory)
function crearValidador(min, max) {
  return (valor) => valor >= min && valor <= max;
}
const validarEdad = crearValidador(0, 120);
const validarPorcentaje = crearValidador(0, 100);

console.log(validarEdad(25));        // true
console.log(validarPorcentaje(150));  // false

// Composicion de funciones
const doble = x => x * 2;
const incrementar = x => x + 1;
const componer = (f, g) => x => f(g(x));
const dobleYSuma = componer(incrementar, doble);
console.log(dobleYSuma(5)); // 11 (5*2 + 1)