1. ¿Qué es una Función? La Máquina de Hacer Pasteles
Una función es un bloque de código reutilizable. Escribes las instrucciones una vez y las usas todas las veces que quieras.
Analogía: La Receta de Cocina
- La Función: Es la receta escrita en el papel.
- Parámetros (Ingredientes): Lo que necesitas para que funcione (Harina, Huevos).
- El Cuerpo (Instrucciones): Batir, hornear, decorar.
- Return (El Resultado): El pastel terminado que sale del horno.
2. Parámetros vs Argumentos: Aclarando Conceptos
Antes de seguir, es importante aclarar dos conceptos que a menudo se confunden:
⚠️ Aclaración Importante
- Parámetro: Es el nombre de la variable que aparece en la definición de la función (cuando la creamos).
- Argumento: Es el valor real que pasamos cuando llamamos a la función.
// En la DEFINICIÓN, "ingrediente" es un PARÁMETRO
function cocinar(ingrediente) {
return "Cocinando " + ingrediente;
}
// En la LLAMADA, "tomate" es un ARGUMENTO
cocinar("tomate");
// También podemos usar una variable como argumento
let miVerdura = "zanahoria";
cocinar(miVerdura); // "zanahoria" es el argumento
🚨 Error Común de Principiantes
Mito: "Si paso una variable como argumento, tiene que llamarse igual que el parámetro."
Realidad: ¡FALSO! Los nombres NO tienen que coincidir. Lo que importa es el valor, no el nombre.
// Esta función tiene un parámetro llamado "numero"
function duplicar(numero) {
return numero * 2;
}
// ✅ CORRECTO: Puedo pasar una variable con CUALQUIER nombre
let edad = 25;
let resultado = duplicar(edad); // edad (25) se copia a numero
// ✅ CORRECTO: Puedo pasar directamente un valor
let otro = duplicar(10);
// ✅ CORRECTO: Puedo usar otra variable con otro nombre
let precio = 50;
let precioDoble = duplicar(precio); // precio (50) se copia a numero
// El parámetro "numero" es solo un contenedor temporal dentro de la función
// Recibe una COPIA del valor que le pasemos, sin importar cómo se llame fuera
Piénsalo así: El parámetro es como una caja con una etiqueta. El argumento es lo que metes dentro de esa caja. La etiqueta puede decir "numero", pero tú puedes meter dentro el contenido de cualquier variable (edad, precio, cantidad, etc.). Lo que importa es el contenido, no cómo se llama fuera.
3. Anatomía de una Función
// 1. Definimos la "máquina"
function saludar(nombre) {
return "¡Hola, " + nombre + "! ¿Qué tal estás?";
}
// 2. Usamos la máquina (Llamar a la función)
let saludo1 = saludar("Ana"); // "¡Hola, Ana! ¿Qué tal estás?"
console.log(saludo1);
Parámetros por Defecto
¿Qué pasa si no le damos ingredientes a la máquina? Podemos poner valores por defecto.
function cocinarPasta(tipo = "Espaguetis") {
return "Cocinando " + tipo;
}
console.log(cocinarPasta("Macarrones")); // "Cocinando Macarrones"
console.log(cocinarPasta()); // "Cocinando Espaguetis" (Usa el defecto)
4. Tipos de Funciones en JavaScript
JavaScript ofrece diferentes formas de crear funciones, cada una con sus propias características y casos de uso óptimos.
4.1 Declaración de Función (Function Declaration)
Es la forma clásica y más común. Se puede llamar antes de su definición gracias al hoisting.
Características
- Definición:
function nombre(params) { ... } - Llamada:
nombre(); - Hoisting: Se puede llamar antes de ser declarada
- Uso ideal: Herramientas lógicas generales y funciones principales
// Definición
function mostrarAlerta(mensaje) {
console.log("ALERTA: " + mensaje);
}
// Llamada directa
mostrarAlerta("Batería baja"); // "ALERTA: Batería baja"
// Ejemplo con return
function calcularIVA(precio) {
return precio * 0.21;
}
let iva = calcularIVA(100); // 21
console.log(iva);
4.2 Expresión de Función (Function Expression)
La función se asigna a una variable. No tiene hoisting, solo se puede usar después de declararla.
Características
- Definición:
const miFuncion = function() { ... }; - Llamada:
miFuncion(); - Hoisting: NO disponible antes de la declaración
- Uso ideal: Cuando necesitas asignar funciones dinámicamente
// Definición
const obtenerDescuento = function(precio) {
return precio * 0.10;
};
// Llamada mediante la variable
console.log(obtenerDescuento(100)); // 10
// Error si intentas usarla antes de declararla
// calcularPrecio(50); // ❌ ERROR: No se puede acceder antes de la inicialización
const calcularPrecio = function(precio) {
return precio * 1.21;
};
4.3 Funciones Flecha (Arrow Functions)
Es la sintaxis moderna introducida en ES6. Más corta, limpia e ideal para operaciones rápidas.
Características
- Definición:
const miFuncion = () => { ... }; - Llamada:
miFuncion(); - Return implícito: Si es una sola línea sin llaves, retorna automáticamente
- Uso ideal: Operaciones rápidas, callbacks, map, filter, reduce
Evolución de la Sintaxis
// Nivel 1: Función Tradicional
// DEFINICIÓN
function sumar(a, b) {
return a + b;
}
// USO
let resultado1 = sumar(5, 3);
console.log(resultado1); // 8
// Nivel 2: Función Flecha (Estándar)
// DEFINICIÓN
const sumarFlecha = (a, b) => {
return a + b;
}
// USO
let resultado2 = sumarFlecha(10, 7);
console.log(resultado2); // 17
// Nivel 3: Return Implícito (¡Solo si es una línea!)
// Si quitas las llaves {}, el return es automático.
// DEFINICIÓN
const sumarRapido = (a, b) => a + b;
// USO
let resultado3 = sumarRapido(20, 15);
console.log(resultado3); // 35
// Nivel 4: Un solo parámetro (Sin paréntesis)
// DEFINICIÓN
const cuadrado = x => x * x;
// USO
let resultado4 = cuadrado(6);
console.log(resultado4); // 36
4.4 Funciones Anónimas (Uso común en Timers)
Son funciones sin nombre, típicamente usadas como callbacks en setTimeout,
setInterval,
o manejadores de eventos.
Características
- No tienen nombre porque solo se necesitan en ese momento
- La "llamada" la gestiona el navegador o el evento
- Uso ideal: Callbacks de eventos o temporizadores únicos
// Ejemplo con setInterval
// La función anónima se ejecuta cada 3000ms
setInterval(function() {
console.log("Han pasado 3 segundos más...");
}, 3000);
// Ejemplo con setTimeout
setTimeout(function() {
console.log("Esto se ejecuta una sola vez después de 2 segundos");
}, 2000);
// También se puede usar con funciones flecha
setInterval(() => {
console.log("Versión moderna con arrow function");
}, 3000);
4.5 IIFE (Immediately Invoked Function Expressions)
Se ejecutan inmediatamente al definirse. Son útiles para inicializar configuraciones que no quieres que nadie toque después.
Características
- Se llaman a sí mismas con los paréntesis finales
() - Crean un ámbito privado (encapsulación)
- Uso ideal: Inicialización de configuraciones, evitar contaminar el scope global
// Ejemplo clásico de IIFE
(function() {
console.log("Configuración del sistema cargada.");
})(); // Se llama a sí misma con los paréntesis finales
// IIFE con parámetros
(function(nombre) {
console.log("Bienvenido, " + nombre);
})("Usuario");
// IIFE con arrow function (ES6)
(() => {
console.log("IIFE moderna con arrow function");
})();
4.6 IIFE + Timers: Capturando Valores en Bucles
Antiguamente, las IIFE eran vitales para que setTimeout o setInterval
recordaran el valor correcto en un bucle. Esto creaba un "escudo" de datos para cada iteración.
⚠️ Problema Clásico con var
Sin IIFE, el temporizador siempre imprimiría el último valor del bucle porque para cuando se ejecuta, el bucle ya terminó.
// ❌ Problema: Sin IIFE (usando var)
for (var i = 1; i <= 3; i++) {
setTimeout(function() {
console.log("Número: " + i); // Imprimirá "4, 4, 4"
}, i * 1000);
}
// ✅ Solución: Con IIFE para capturar el valor
for (var i = 1; i <= 3; i++) {
// Usamos una IIFE para capturar el valor actual de 'i'
(function(indiceCapturado) {
setTimeout(function() {
console.log("Contador: " + indiceCapturado); // "1, 2, 3"
}, indiceCapturado * 1000);
})(i); // Le pasamos 'i' a la IIFE inmediatamente
}
// 🎯 Solución Moderna: Usar 'let' en lugar de 'var'
// Con 'let', cada iteración tiene su propio scope
for (let i = 1; i <= 3; i++) {
setTimeout(function() {
console.log("Número: " + i); // Imprimirá "1, 2, 3"
}, i * 1000);
}
4.7 Tabla Resumen: ¿Cuándo usar cada tipo?
| Situación | Función recomendada | Ejemplo |
|---|---|---|
| Definir una herramienta lógica general | Declaración | function calcular() {...} |
| Asignar funciones dinámicamente | Expresión | const fn = function() {...} |
| Pasar una función rápida a map/filter | Flecha (Arrow) | arr.map(x => x * 2) |
| Programar una tarea repetitiva | Anónima o Flecha | setInterval(() => {...}, 1000) |
| Ejecutar código inmediatamente al cargar | IIFE | (function() {...})() |
| Capturar valores en bucles con timers | IIFE + Timers o let | (function(i) {...})(i) |
5. Scope (Alcance): ¿Dónde viven mis variables?
Esto es crucial. Las variables no son visibles desde todas partes.
La Casa vs La Habitación
- Global (La Casa): Si dejas las llaves en el salón, todos pueden cogerlas.
- Local (La Habitación): Si tienes una tele en tu cuarto y cierras la puerta, solo tú puedes verla.
let variableGlobal = "Soy visible para todos";
function miFuncion() {
let variableLocal = "Soy secreta";
console.log(variableGlobal); // Funciona (Ve el exterior)
}
miFuncion();
// console.log(variableLocal); // ¡ERROR! No puedes ver dentro de la función