Declaración, parámetros y retorno
Una función es una máquina: le entra materia prima
(parámetros), trabaja con ella y devuelve un resultado
(return). Se define una vez y se usa mil veces.
function precioConIva(precio, tipoIva) {
const total = precio * (1 + tipoIva);
return total;
}
const factura = precioConIva(100, 0.21);
console.log(factura); // 121
| Término | Es… | Ejemplo |
|---|---|---|
| Parámetro | el nombre en la DECLARACIÓN | (precio, tipoIva) |
| Argumento | el valor real en la LLAMADA | precioConIva(100, 0.21) |
| return | devuelve el resultado y TERMINA la función | return total; |
console.log() con return — loguear MUESTRA, return ENTREGA el
valor para poder seguir trabajándolo. 2) Una función sin
return devuelve undefined.1.1 · return corta la ejecución
Nada que venga después de un return ejecutado se llega a leer. Esto permite
escaleras de decisiones limpias, conectando con el Bloque 2:
function clasificar(nota) {
if (nota >= 9) return "Sobresaliente";
if (nota >= 5) return "Aprobado";
return "Suspenso"; // el resto de casos
}
calcularYMostrar, sospecha: separa el cálculo (con return) del mostrar
(con console.log).Expresiones, flechas y valores por defecto
Además de declararse, una función puede nacer dentro de una constante. Y desde ES6 existe la forma compacta que verás en TODO código moderno: las arrow functions.
| Estilo | Sintaxis |
|---|---|
| Declaración | function doble(n) { return n * 2; } |
| Expresión | const doble = function (n) { return n * 2; }; |
| Flecha | const doble = n => n * 2; |
2.1 · La flecha y sus tres niveles de compacidad
// ① cuerpo clásico: llaves OBLIGAN a escribir return
const area = (base, altura) => {
const resultado = base * altura;
return resultado;
};
// ② retorno implícito: sin llaves, la expresión SE DEVUELVE sola
const areaCorta = (base, altura) => base * altura;
// ③ un único parámetro: paréntesis opcionales
const doble = n => n * 2;
undefined. Si necesitas varias líneas, no olvides el return; si es una sola
expresión, quita las llaves y olvídate.2.2 · Parámetros por defecto
Un parámetro puede traer valor de fábrica: si la llamada no lo envía, se usa ese:
function total(precio, iva) {
return precio + precio * iva;
}
total(100);
// 100 + 100 * undefined → NaN 💥
function total(precio, iva = 0.21) {
return precio + precio * iva;
}
total(100); // 121 ✔️ usa el default
total(100, 0.10); // 110 ✔️ usa el enviado
Scope, hoisting y closures
Las variables tienen vida propia limitada: el scope (ámbito) es la zona del programa donde existen. Lo declarado dentro de una función solo existe allí dentro.
const web = "TécnicoWeb"; // GLOBAL: visible en todo el script
function visitar() {
const minuto = 3; // LOCAL: solo vive dentro de visitar()
console.log(web); // ✔️ leer hacia afuera SÍ se puede
}
console.log(minuto); // ❌ ReferenceError: no existe aquí fuera
- Hacia dentro, sí; hacia fuera, no: una función ve las variables globales y las suyas, pero nadie ve las locales de la función.
- Por eso los parámetros son tan valiosos: entran datos por la puerta en vez de depender de globals.
3.1 · Hoisting: el elevador
Las declaraciones function se «elevan» al inicio de su ámbito: puedes
llamarlas ANTES de escribirlas. Las const/let NO: usarlas antes de
declararlas lanza error.
saludar(); // ¡funciona!
function saludar() {
console.log("Hola");
}
saludar(); // ReferenceError 💥
const saludar = () => {
console.log("Hola");
};
3.2 · Closures: la mochila con memoria
Cuando una función nace DENTRO de otra, guarda acceso a las variables de su entorno aunque la exterior ya haya terminado. Eso es un closure:
function crearContador() {
let cuenta = 0; // vive en la mochila del closure
return function () {
cuenta++;
return cuenta;
};
}
const siguiente = crearContador();
console.log(siguiente()); // 1
console.log(siguiente()); // 2 — ¡recuerda su cuenta!
cuenta: ni leerla ni resetearla.
Los closures son la forma natural de crear estado PRIVADO. Volverán en el Bloque 8 con
fuerza.Callbacks y funciones puras
En JavaScript las funciones son valores: se guardan en constantes, se pasan por parámetros y se devuelven como resultados. Una función que recibe otra para ejecutarla recibe el nombre de higher-order function, y a la función pasada le llamamos callback.
function operar(a, b, operacion) {
return operacion(a, b); // ejecuta LO QUE LLEGUE
}
function sumar(x, y) { return x + y; }
function multiplicar(x, y) { return x * y; }
console.log(operar(3, 4, sumar)); // 7
console.log(operar(3, 4, multiplicar)); // 12
console.log(operar(10, 5, (x, y) => x - y)); // 5 — callback anónimo
sumar SIN paréntesis. Si escribieras
sumar(3, 4) estarías EJECUTÁNDOLA y pasando su resultado; sin paréntesis
pasas LA FUNCIÓN misma para que la ejecute quien reciba.4.1 · Pura o impura: el sello de calidad
| Condición | Significa… |
|---|---|
| Mismos argumentos → mismo resultado, SIEMPRE | No depende de variables externas mutables ni del azar |
| No provoca efectos externos | No modifica globals, ni imprime, ni cambia nada ajeno a ella |
function descuento(precio, pct) {
return precio - precio * pct;
}
// descuento(100, .2) vale 80
// hoy, mañana y siempre
let ivaGlobal = 0.21;
function total(precio) {
ivaGlobal = 0.25; // efecto externo 💥
return precio * (1 + ivaGlobal);
}
console.log() es impura (imprime = efecto externo): úsala PARA VER resultados,
pero mantén el cálculo en funciones puras. Este principio domina el Bloque 5.✍️ Los 16 ejercicios del bloque
Crea la carpeta js-b3/ y resuelve en orden — cada ejercicio encadena el
anterior. Trabaja en archivos ej01.html, ej02.html… con un
<script> al final del body y abre la consola (F12).
Sección A · Declaración y retorno
1 Tu primera función
Declara saludar(nombre) que imprima «Bienvenida/o, ___» con template
literal. Llámala dos veces con nombres distintos.
Ver solución
function saludar(nombre) {
console.log(`Bienvenida/o, ${nombre}`);
}
saludar("Ada");
saludar("Alan");
2 Máquina de dobles
doble(n) debe DEVOLVER (no imprimir) el número multiplicado por 2.
Guarda dos resultados en constantes y muéstralos con un único console.log.
Ver solución
function doble(n) {
return n * 2;
}
const d1 = doble(7);
const d2 = doble(125);
console.log(d1, d2); // 14 250
3 Área y perímetro
Dos funciones: area(base, altura) y perimetro(base, altura),
ambas con return. Muéstralas juntas formateando con template literal.
Ver solución
function area(base, altura) {
return base * altura;
}
function perimetro(base, altura) {
return 2 * (base + altura);
}
const b = 4;
const h = 3;
console.log(`Área: ${area(b, h)} · Perímetro: ${perimetro(b, h)}`);
4 Boolean factory
esMayorDeEdad(edad) devuelve edad >= 18 directamente
(¡una comparación YA es un boolean!). Fuera de la función, usa su resultado dentro de un
if/else.
Ver solución
function esMayorDeEdad(edad) {
return edad >= 18;
}
if (esMayorDeEdad(16)) {
console.log("Entra");
} else {
console.log("A casa, peque");
}
5 Returns en cascada
clasificarVelocidad(kmh) devuelve «Peatón» (< 10), «Ciudad»
(< 60), «Autovía» (< 120) o «Excesivo». Cada rama con SU return. Prueba 5, 50, 100
y 180.
Ver solución
function clasificarVelocidad(kmh) {
if (kmh < 10) return "Peatón";
if (kmh < 60) return "Ciudad";
if (kmh < 120) return "Autovía";
return "Excesivo";
}
console.log(clasificarVelocidad(5));
console.log(clasificarVelocidad(50));
console.log(clasificarVelocidad(100));
console.log(clasificarVelocidad(180));
Sección B · Flechas y valores por defecto
6 De function a flecha
Rewrite del ejercicio 2 como arrow function de retorno implícito:
const dobleFlecha = n => n * 2;. Comprueba que da los mismos resultados.
Ver solución
const dobleFlecha = n => n * 2;
console.log(dobleFlecha(7), dobleFlecha(125)); // 14 250 ✔️
7 Flecha con cuerpo
ficha(nombre, ciudad) como arrow MULTILÍNEA (con llaves) que construya y
devuelva la frase «___ vive en ___». Recuerda: con llaves, return obligatorio.
Ver solución
const ficha = (nombre, ciudad) => {
const frase = `${nombre} vive en ${ciudad}.`;
return frase;
};
console.log(ficha("Ada", "Madrid"));
8 IVA configurable
precioTotal(precio, iva = 0.21) devuelve el precio con IVA. Llama a la
función una vez SIN segundo argumento y otra CON 0.10.
Ver solución
function precioTotal(precio, iva = 0.21) {
return precio + precio * iva;
}
console.log(precioTotal(100)); // 121 (default)
console.log(precioTotal(100, 0.10)); // 110
9 Saludos configurables
saludo(nombre, mensaje = "Hola") devuelve «mensaje, nombre!».
Pruébalo con y sin segundo argumento.
Ver solución
function saludo(nombre, mensaje = "Hola") {
return `${mensaje}, ${nombre}!`;
}
console.log(saludo("Ada")); // Hola, Ada!
console.log(saludo("Ada", "Bienvenida")); // Bienvenida, Ada!
Sección C · Scope y closures
10 Mapa del scope
Declara una constante global web y dentro de una función una variable
local visita. Dentro de la función imprime AMBAS; fuera, intenta imprimir
la local y observa el ReferenceError.
Ver solución
const web = "TécnicoWeb";
function registrar() {
let visita = "paseo 14:00";
console.log(web); // ✔️ global visible
console.log(visita); // ✔️ local visible aquí
}
registrar();
console.log(visita); // ❌ ReferenceError: visita is not defined
11 Contadores gemelos
Reproduce crearContador() de la Lección 3.2. Crea DOS contadores
(cA y cB) y demuestra que cada uno lleva SU propia cuenta
alternando llamadas.
Ver solución
function crearContador() {
let cuenta = 0;
return () => {
cuenta++;
return cuenta;
};
}
const cA = crearContador();
const cB = crearContador();
console.log(cA()); // 1
console.log(cB()); // 1 — mochila independiente
console.log(cA()); // 2
12 Fábrica con memoria
crearGenerador(prefijo) devuelve una función que devuelve
«prefijo-001», «prefijo-002»… con contador interno. Genera dos
IDs de pedido.
Ver solución
function crearGenerador(prefijo) {
let consecutivo = 0;
return () => {
consecutivo++;
return `${prefijo}-${String(consecutivo).padStart(3, "0")}`;
};
}
const siguientePedido = crearGenerador("PED");
console.log(siguientePedido()); // PED-001
console.log(siguientePedido()); // PED-002
Sección D · Callbacks y pureza
13 El ejecutor
ejecutar(accion) debe llamar a accion() tres veces. Pásale
como callback una flecha que imprima «Tic».
Ver solución
function ejecutar(accion) {
accion();
accion();
accion();
}
ejecutar(() => console.log("Tic")); // Tic × 3
14 Repetidor configurable
repetirVeces(n, accion) ejecuta accion(i) en cada vuelta,
pasándole el índice. Llámalo con una flecha que muestre «Vuelta i de n».
Ver solución
function repetirVeces(n, accion) {
for (let i = 1; i <= n; i++) {
accion(i);
}
}
repetirVeces(4, i => console.log(`Vuelta ${i} de 4`));
15 Calculadora por callback
Reproduce el patrón operar(a, b, operacion) de la Lección 4. Declara
sumar, restar y multiplicar, y llama a
operar con las tres (¡sin paréntesis al pasarlas!).
Ver solución
function sumar(x, y) { return x + y; }
function restar(x, y) { return x - y; }
function multiplicar(x, y) { return x * y; }
function operar(a, b, operacion) {
return operacion(a, b);
}
console.log(operar(10, 3, sumar)); // 13
console.log(operar(10, 3, restar)); // 7
console.log(operar(10, 3, multiplicar)); // 30
16 🏆 Proyecto integrador: caja-registradora.html
Crea caja-registradora.html. Requisitos mínimos:
- Dos funciones declaradas con comentarios
/** … */encima. total(precioBase, unidades = 1): pura, con parámetro por defecto.- Una arrow function para formatear el ticket.
- Una higher-order function que reciba un callback
(
aplicarDescuento(importe, criterio)). - Llama a alguna función al menos dos veces.
- Nada de globals mutables: todo entra por parámetros y sale por return.
Ver solución modelo
/**
* Calcula el importe bruto.
*/
function total(precioBase, unidades = 1) {
return precioBase * unidades;
}
/**
* Aplica descuento solo si el criterio lo aprueba.
*/
function aplicarDescuento(importe, criterio) {
if (criterio(importe)) {
return importe * 0.9;
}
return importe;
}
const etiqueta = importe => `Total: ${importe.toFixed(2)} €`;
console.log(etiqueta(aplicarDescuento(total(25, 2), i => i > 50)));
console.log(etiqueta(total(9)));
📝 Examen del Bloque 3
Necesitas ≥ 70 % (10/14) para superar el bloque.
Parte B · Reto práctico final
Construye el ejercicio 16 («caja-registradora.html») sin mirar soluciones y valida tú mismo/a estos criterios. Mínimo para aprobar: 7 de 8 casillas.
Cumplidos: 0 / 8