Tema
Funciones
Las funciones son el corazón de JavaScript. Te permiten empaquetar un conjunto de instrucciones, darle un nombre y reutilizarlo cuantas veces quieras. Calcular el IVA, validar un correo, mostrar un producto en pantalla: todo eso se convierte en funciones. En esta lección aprenderás las tres formas de crearlas, cómo pasarles datos, cómo devolver resultados y qué son los callbacks y las funciones puras.
Concepto
Una función es como una receta de cocina:
- Tiene un nombre: "Agua de horchata".
- Recibe ingredientes (parámetros): arroz, canela, azúcar.
- Sigue pasos (el cuerpo de la función).
- Entrega un resultado (el valor de retorno): una jarra de agua.
Escribes la receta una vez y la preparas (la llamas) cuando quieras, con distintos ingredientes.
js
// nombre parámetros
function calcularIVA(precio) {
return precio * 0.16; // resultado
}
calcularIVA(100); // llamada → 16
calcularIVA(250); // llamada → 40¿Por qué usar funciones?
- Reutilizar: escribes la lógica una vez.
- Organizar: divides un problema grande en piezas pequeñas.
- Mantener: si cambia el IVA, lo corriges en un solo lugar.
- Leer mejor:
aplicarDescuento(total)se entiende mejor que cinco líneas de cálculos.
Tres formas de crear funciones
1. Declaración de función
js
function saludar(nombre) {
return `Hola, ${nombre}`;
}
console.log(saludar('Ana')); // "Hola, Ana"Las declaraciones tienen hoisting completo: puedes llamarlas incluso antes de la línea donde las escribiste.
js
console.log(sumar(2, 3)); // 5 ✅ funciona
function sumar(a, b) {
return a + b;
}2. Expresión de función
Guardas una función (normalmente anónima) en una variable:
js
const despedir = function (nombre) {
return `Hasta luego, ${nombre}`;
};
console.log(despedir('Luis')); // "Hasta luego, Luis"Aquí no hay hoisting útil: si la llamas antes de definirla, obtienes un error (por la TDZ de const, que viste en Variables y tipos).
3. Funciones flecha (arrow functions)
La sintaxis moderna y compacta (ES6):
js
// Forma completa
const multiplicar = (a, b) => {
return a * b;
};
// Si sólo devuelve una expresión, puedes omitir llaves y return
const multiplicarCorto = (a, b) => a * b;
// Con un solo parámetro, los paréntesis son opcionales
const doble = n => n * 2;
// Sin parámetros, paréntesis vacíos
const obtenerFecha = () => new Date().toLocaleDateString('es-MX');
// Para devolver un objeto directamente, envuélvelo en paréntesis
const crearProducto = (nombre, precio) => ({ nombre, precio });
console.log(multiplicarCorto(4, 5)); // 20
console.log(doble(8)); // 16
console.log(crearProducto('Taza', 120)); // { nombre: 'Taza', precio: 120 }¿Cuál uso?
- Declaraciones (
function nombre()): para funciones principales de tu programa. - Flechas: para funciones cortas y callbacks (lo más común en código moderno).
Las flechas tienen una diferencia técnica con this que verás en POO y clases. Por ahora, ambas te sirven igual.
Parámetros y argumentos
- Parámetros: los nombres que pones al definir la función (
precio,cantidad). - Argumentos: los valores reales que pasas al llamarla (
250,3).
js
function calcularSubtotal(precio, cantidad) { // parámetros
return precio * cantidad;
}
calcularSubtotal(250, 3); // argumentos → 750Si pasas menos argumentos, los que faltan valen undefined:
js
calcularSubtotal(250); // 250 * undefined → NaNParámetros por defecto
js
function calcularSubtotal(precio, cantidad = 1) {
return precio * cantidad;
}
calcularSubtotal(250); // 250 (cantidad = 1)
calcularSubtotal(250, 4); // 1000
// Pueden depender de parámetros anteriores
function crearUsuario(nombre, rol = 'cliente', saludo = `Bienvenido, ${nombre}`) {
return { nombre, rol, saludo };
}
console.log(crearUsuario('Sofía'));
// { nombre: 'Sofía', rol: 'cliente', saludo: 'Bienvenido, Sofía' }Parámetros rest (...)
Para recibir cualquier cantidad de argumentos como un array:
js
function sumarTodo(...numeros) {
let total = 0;
for (const n of numeros) {
total += n;
}
return total;
}
console.log(sumarTodo(10, 20)); // 30
console.log(sumarTodo(5, 15, 25, 35)); // 80
// Se pueden combinar con parámetros normales (rest siempre al final)
function registrarPedido(cliente, ...productos) {
console.log(`${cliente} pidió ${productos.length} productos:`, productos);
}
registrarPedido('Ana', 'Café', 'Pan', 'Jugo');return: devolver resultados
return hace dos cosas: entrega un valor y termina la función inmediatamente.
js
function obtenerDescuento(total) {
if (total >= 2000) return 0.10; // sale aquí si se cumple
if (total >= 1000) return 0.05;
return 0; // valor por defecto
}
const descuento = obtenerDescuento(1500); // 0.05Si una función no tiene return, devuelve undefined:
js
function saludar(nombre) {
console.log(`Hola, ${nombre}`); // imprime, pero no devuelve
}
const resultado = saludar('Ana'); // imprime "Hola, Ana"
console.log(resultado); // undefinedError común
Confundir imprimir con devolver. console.log sólo muestra algo en la consola; no te da el valor para seguir usándolo. Si necesitas el resultado para otro cálculo, usa return.
js
// ❌
function calcularTotal(precio) {
console.log(precio * 1.16);
}
const total = calcularTotal(100); // undefined
// ✅
function calcularTotalBien(precio) {
return precio * 1.16;
}
const totalBien = calcularTotalBien(100); // 116Callbacks: funciones como argumentos
En JavaScript las funciones son valores: puedes guardarlas en variables, meterlas en arrays y pasarlas a otras funciones. Una función que se pasa como argumento se llama callback.
js
// Una función que recibe otra función
function procesarPedido(pedido, alTerminar) {
console.log(`Procesando pedido #${pedido}...`);
alTerminar(pedido); // llamamos al callback
}
function enviarCorreo(id) {
console.log(`📧 Correo de confirmación enviado para el pedido #${id}`);
}
procesarPedido(1024, enviarCorreo);
// Procesando pedido #1024...
// 📧 Correo de confirmación enviado para el pedido #1024
// También se puede pasar una función flecha directamente
procesarPedido(1025, (id) => console.log(`Pedido ${id} listo`));Usarás callbacks todo el tiempo:
js
// Eventos: "cuando hagan clic, ejecuta esta función"
boton.addEventListener('click', () => {
console.log('¡Clic!');
});
// Temporizadores: "en 2 segundos, ejecuta esto"
setTimeout(() => {
console.log('Pasaron 2 segundos');
}, 2000);
// Métodos de arrays: "para cada producto, haz esto"
const precios = [100, 200, 300];
const conIVA = precios.map((precio) => precio * 1.16);
console.log(conIVA); // [116, 232, 348]Error común
Llamar al callback en lugar de pasarlo:
js
// ❌ Ejecuta saludar AHORA y pasa su resultado (undefined)
boton.addEventListener('click', saludar());
// ✅ Pasa la función para que se ejecute DESPUÉS
boton.addEventListener('click', saludar);Funciones puras
Una función es pura cuando:
- Con los mismos argumentos, siempre devuelve el mismo resultado.
- No modifica nada fuera de ella (no tiene efectos secundarios).
js
// ✅ Pura: sólo depende de sus parámetros
function aplicarDescuento(precio, porcentaje) {
return precio - precio * (porcentaje / 100);
}
// ❌ Impura: depende y modifica una variable externa
let total = 0;
function agregarAlTotal(precio) {
total += precio; // efecto secundario
return total;
}
// ❌ Impura: modifica el array que recibe
function agregarProducto(carrito, producto) {
carrito.push(producto);
return carrito;
}
// ✅ Versión pura: devuelve un array NUEVO
function agregarProductoPuro(carrito, producto) {
return [...carrito, producto];
}Las funciones puras son más fáciles de probar, depurar y reutilizar. No todo puede ser puro (mostrar algo en pantalla o guardar datos son efectos secundarios necesarios), pero procura que la lógica de cálculo sí lo sea.
Buena práctica
- Una función debe hacer una sola cosa y hacerla bien.
- Nombra las funciones con verbos:
calcularTotal,validarEmail,mostrarProductos. - Si una función pasa de ~20–30 líneas, probablemente puedes dividirla.
- Separa la lógica (funciones puras que calculan) de la interfaz (funciones que tocan el DOM).
Ejemplo completo: carrito sencillo
js
// Lógica pura: calcula, no toca nada externo
const calcularSubtotal = (productos) => {
let suma = 0;
for (const p of productos) {
suma += p.precio * p.cantidad;
}
return suma;
};
const calcularEnvio = (subtotal, envioGratisDesde = 999) =>
subtotal >= envioGratisDesde ? 0 : 99;
const formatearPrecio = (cantidad) => `$${cantidad.toFixed(2)} MXN`;
// Función que orquesta todo
function resumenCarrito(productos) {
const subtotal = calcularSubtotal(productos);
const envio = calcularEnvio(subtotal);
const total = subtotal + envio;
return {
subtotal: formatearPrecio(subtotal),
envio: envio === 0 ? 'Gratis' : formatearPrecio(envio),
total: formatearPrecio(total),
};
}
const carrito = [
{ nombre: 'Playera', precio: 250, cantidad: 2 },
{ nombre: 'Gorra', precio: 180, cantidad: 1 },
];
console.log(resumenCarrito(carrito));
// { subtotal: '$680.00 MXN', envio: '$99.00 MXN', total: '$779.00 MXN' }Ejercicios
- Crea una función flecha
celsiusAFahrenheit(c)que devuelva la conversión (c * 9 / 5 + 32). - Crea
crearSaludo(nombre, idioma = 'es')que devuelva'Hola, X'en español o'Hello, X'en inglés. - Crea
promedio(...calificaciones)que reciba cualquier cantidad de números y devuelva su promedio. Si no recibe ninguno, debe devolver0. - Crea
repetir(veces, accion)que ejecute el callbackaccionla cantidad de veces indicada, pasándole el número de vuelta.
Ver solución
1.
js
const celsiusAFahrenheit = (c) => c * 9 / 5 + 32;
console.log(celsiusAFahrenheit(30)); // 862.
js
function crearSaludo(nombre, idioma = 'es') {
return idioma === 'en' ? `Hello, ${nombre}` : `Hola, ${nombre}`;
}
console.log(crearSaludo('Ana')); // "Hola, Ana"
console.log(crearSaludo('Ana', 'en')); // "Hello, Ana"3.
js
function promedio(...calificaciones) {
if (calificaciones.length === 0) return 0;
let suma = 0;
for (const c of calificaciones) {
suma += c;
}
return suma / calificaciones.length;
}
console.log(promedio(8, 9, 10)); // 9
console.log(promedio()); // 04.
js
function repetir(veces, accion) {
for (let i = 1; i <= veces; i++) {
accion(i);
}
}
repetir(3, (n) => console.log(`Vuelta ${n}`));
// Vuelta 1
// Vuelta 2
// Vuelta 3Resumen
- Una función agrupa instrucciones reutilizables; se define una vez y se llama muchas veces.
- Tres formas: declaración (con hoisting), expresión y flecha (compacta, ideal para callbacks).
- Los parámetros por defecto evitan
undefined; los rest (...) reciben muchos argumentos como array. returndevuelve un valor y termina la función; sinreturn, devuelveundefined.- Un callback es una función que pasas a otra para que la ejecute después.
- Las funciones puras no tienen efectos secundarios y siempre dan el mismo resultado.
Siguiente: Scope y closures