La lección anterior terminó con una limitación: pesoDePrioridad y describirTarea son declaraciones con nombre fijo, disponibles siempre y siempre iguales. Pero en Nómada Tareas vas a necesitar algo más flexible: una tabla que asocie cada estado con la función que lo formatea, una lista de validadores que se recorra con un bucle, o una función que se elija en tiempo de ejecución según lo que haya pedido Marta. Todo eso es posible porque en JavaScript una función es un valor, exactamente igual que un número o un texto: se puede guardar en una variable, meter en un array, poner dentro de un objeto y pasar como argumento. En esta lección aprenderás las dos formas de escribir funciones como valores —la expresión de función y la función flecha—, cuándo usar cada una y qué diferencias reales hay entre ellas.
Contenido
- Las funciones son valores de primera clase
- La expresión de función
- Expresión de función con nombre
- La función flecha: la sintaxis completa
- Devolver un objeto literal desde una flecha
- Tabla comparativa: declaración vs expresión vs flecha
- La flecha y
this: lo que necesitas saber hoy - Un objeto de formateadores para Nómada Tareas
- Una tabla de validadores recorrible
- IIFE: la función que se llama a sí misma al nacer
- Cuándo elegir cada forma
- Errores Comunes y Consejos
- Ejercicios
- Conclusión
- Las funciones son valores de primera clase
Decir que las funciones son ciudadanos de primera clase (first-class citizens) significa que el lenguaje las trata como a cualquier otro valor. Compruébalo con la función de la lección anterior:
function pesoDePrioridad(prioridad) {
if (prioridad === 'alta') return 3;
if (prioridad === 'media') return 2;
if (prioridad === 'baja') return 1;
return 0;
}
// 1. Se puede asignar a una variable
const calcularPeso = pesoDePrioridad;
console.log(calcularPeso('alta')); // 3
// 2. Se puede meter en un array
const operaciones = [pesoDePrioridad];
console.log(operaciones[0]('media')); // 2
// 3. Se puede guardar en un objeto
const utilidades = { peso: pesoDePrioridad };
console.log(utilidades.peso('baja')); // 1
// 4. Se puede inspeccionar
console.log(typeof pesoDePrioridad); // 'function'
console.log(pesoDePrioridad.name); // 'pesoDePrioridad'
console.log(pesoDePrioridad.length); // 1 (número de parámetros declarados)Fíjate en la línea const calcularPeso = pesoDePrioridad;: no hay paréntesis. No se está llamando a la función, se está copiando la referencia a la función. Ahora hay dos nombres apuntando al mismo trozo de código. Esto conecta directamente con lo que aprendiste en Variables y Tipos de Datos: las funciones son valores de referencia, como los objetos y los arrays.
Y ese es el mecanismo que hace posible todo lo que viene después: si una función es un valor, se puede pasar a otra función (lo verás en Funciones de Orden Superior) y se puede elegir en tiempo de ejecución.
- La expresión de función
Una expresión de función es una función escrita en el sitio donde iría un valor. La más habitual es asignarla a una constante:
const estaVencida = function (fechaLimite, estado, hoy) {
return fechaLimite < hoy && estado !== 'hecha';
};
console.log(estaVencida('2026-09-05', 'pendiente', '2026-09-20')); // trueTres detalles de sintaxis que conviene marcar:
- Después de
functionno hay nombre. Se dice que es una función anónima. - La constante
estaVencidaes la que da nombre práctico a la función. - Hay punto y coma al final, porque toda la línea es una asignación (una sentencia), no una declaración.
La diferencia práctica más importante con la declaración es cuándo existe:
console.log(declarada('alta')); // 3 ✓ funciona
function declarada(p) { return p === 'alta' ? 3 : 1; }
console.log(expresada('alta')); // ✗ ReferenceError: Cannot access 'expresada' before initialization
const expresada = function (p) { return p === 'alta' ? 3 : 1; };Una declaración de función está lista antes de que empiece la ejecución; una expresión asignada a const o let no existe hasta que la línea se ejecuta. El mecanismo completo (el hoisting y la zona muerta temporal) lo estudiarás en Hoisting y el Contexto de Ejecución. La consecuencia práctica de hoy: con expresiones, defina antes de usar.
Esa restricción, que parece un inconveniente, en realidad es una ventaja: obliga a un orden de lectura natural de arriba abajo y evita el estilo desordenado en el que las funciones aparecen después de usarse.
- Expresión de función con nombre
Se puede poner un nombre a la función y además asignarla a una variable. Se llama named function expression:
const calcularUrgencia = function calcularUrgenciaInterna(prioridad, diasRestantes) {
if (diasRestantes < 0) return 100;
return pesoDePrioridad(prioridad) * 10 - diasRestantes;
};¿Para qué sirve ese nombre interno, si para llamarla se usa calcularUrgencia?
| Ventaja | Explicación |
|---|---|
| Trazas de error legibles | En el stack de un Error aparece calcularUrgenciaInterna en vez de <anonymous> |
| Autorreferencia | Dentro del cuerpo puedes llamarte a ti misma por ese nombre, útil en recursividad (ver Recursividad) |
| No contamina fuera | calcularUrgenciaInterna solo existe dentro del cuerpo; fuera da ReferenceError |
console.log(calcularUrgencia.name); // 'calcularUrgenciaInterna'
console.log(typeof calcularUrgenciaInterna); // ✗ ReferenceErrorEn la práctica se usa poco, porque los motores modernos ya infieren el nombre de la variable:
const estaVencida = function (f, e, h) { return f < h && e !== 'hecha'; };
console.log(estaVencida.name); // 'estaVencida' ← inferido de la constante
- La función flecha: la sintaxis completa
La función flecha (arrow function), introducida en ES2015, es una forma más breve de escribir una expresión de función. Su sintaxis tiene varias formas según lo que necesites, y conviene conocerlas todas porque las verás mezcladas en cualquier código real.
4.1 Cuerpo de bloque
Es la traducción literal de una expresión de función: quitas function y pones => entre los paréntesis y las llaves.
const estaVencida = (fechaLimite, estado, hoy) => {
return fechaLimite < hoy && estado !== 'hecha';
};Con llaves, el return es obligatorio si quieres devolver algo.
4.2 Retorno implícito
Si el cuerpo es una sola expresión, puedes quitar las llaves y el return. El valor de esa expresión se devuelve automáticamente:
Esta es la forma que más verás en el código profesional para funciones pequeñas.
4.3 Un solo parámetro
Con exactamente un parámetro, los paréntesis son opcionales:
Muchos equipos configuran su linter para exigir siempre los paréntesis ((texto) => ...), porque así añadir un segundo parámetro no obliga a reescribir la línea. En Calidad de Código verás cómo se automatiza esa decisión.
4.4 Sin parámetros
Los paréntesis vacíos son obligatorios:
4.5 Resumen de formas
| Forma | Sintaxis | Cuándo usarla |
|---|---|---|
| Bloque | (a, b) => { ...; return x; } |
Varias sentencias, guardas, variables internas |
| Retorno implícito | (a, b) => a + b |
Una sola expresión |
| Un parámetro | a => a * 2 |
Transformaciones simples |
| Sin parámetros | () => 'valor' |
Constantes calculadas, fábricas |
| Objeto literal | (a) => ({ clave: a }) |
Ver apartado siguiente |
- Devolver un objeto literal desde una flecha
Aquí hay una trampa sintáctica que confunde a todo el mundo la primera vez. Esto no funciona como esperas:
const resumir = (titulo, horas) => { titulo: titulo, horas: horas };
console.log(resumir('Actualizar la web de reservas', 14)); // undefinedEl motor interpreta esas llaves como un bloque de código, no como un objeto literal. Dentro del bloque, titulo: parece una etiqueta (como las break etiqueta de break, continue y Bucles Anidados), no hay return, y la función devuelve undefined.
La solución es envolver el objeto en paréntesis, para que el motor sepa que es una expresión:
const resumir = (titulo, horas) => ({ titulo: titulo, horas: horas });
console.log(resumir('Actualizar la web de reservas', 14));
// { titulo: 'Actualizar la web de reservas', horas: 14 }Regla para recordarlo: llaves = bloque; paréntesis + llaves = objeto.
flowchart TD
A["(x) => { ... }"] --> B["Las llaves son un BLOQUE<br/>Necesitas return explícito"]
C["(x) => ({ ... })"] --> D["Los paréntesis fuerzan EXPRESIÓN<br/>Devuelve el objeto"]
- Tabla comparativa: declaración vs expresión vs flecha
Esta es la tabla que conviene tener a mano hasta que las diferencias se te queden grabadas:
| Aspecto | Declaraciónfunction f() {} |
Expresiónconst f = function () {} |
Flechaconst f = () => {} |
|---|---|---|---|
| Se puede llamar antes de definirla | Sí (hoisting completo) | No (TDZ de const/let) |
No (TDZ de const/let) |
| Tiene nombre propio | Sí, siempre | Opcional (anónima o con nombre) | No; se infiere de la variable |
this propio |
Sí | Sí | No: hereda el del entorno |
Objeto arguments |
Sí | Sí | No |
Se puede usar con new |
Sí | Sí | No (TypeError) |
| Retorno implícito | No | No | Sí, si el cuerpo es una expresión |
| Sintaxis más breve | No | No | Sí |
| Uso típico | Funciones principales del módulo | Funciones asignadas condicionalmente | Callbacks y funciones de una línea |
Tres de esas filas necesitan aclaración inmediata:
argumentses un objeto legado que contiene todos los argumentos recibidos aunque no estén declarados como parámetros. Lo verás en Parámetros y Valores de Retorno, junto con su sustituto moderno, los parámetros rest. Las flechas no lo tienen.newsirve para crear objetos con funciones constructoras; es materia de Prototipos y Herencia. Con una flecha da error, y eso es deliberado.thismerece su propio apartado.
- La flecha y
this: lo que necesitas saber hoy
this: lo que necesitas saber hoythis es una palabra clave cuyo valor depende de cómo se llama a la función. Es un tema con matices suficientes para una lección entera, y la tiene: Métodos de Objeto y this. Hoy solo necesitas grabar una frase:
Una función flecha no tiene su propio
this: usa el del ámbito donde fue escrita.
De ahí se derivan las dos consecuencias prácticas que te encontrarás:
- No uses una flecha como método de un objeto cuando el método necesite acceder a los datos de ese objeto. La flecha no "verá" el objeto.
- Sí usa una flecha para funciones que se pasan a otra función (callbacks, manejadores de eventos del Módulo 6), porque conserva el
thisde alrededor y eso suele ser justo lo que quieres.
Un ejemplo mínimo, solo para que reconozcas el síntoma cuando aparezca:
const panel = {
titulo: 'Backlog de Taller Nómada',
conFuncion: function () {
return this.titulo; // 'Backlog de Taller Nómada'
},
conFlecha: () => {
return this.titulo; // undefined ← la flecha no ve el objeto
}
};
console.log(panel.conFuncion()); // Backlog de Taller Nómada
console.log(panel.conFlecha()); // undefinedNo intentes entender ahora por qué: solo recuerda el patrón. En 04-02 lo desmontarás pieza a pieza. Nada de lo que escribas en este módulo depende de this.
- Un objeto de formateadores para Nómada Tareas
Aquí es donde las funciones como valores empiezan a pagar. En el Módulo 2 formateabas cada campo con switch o cadenas de if repartidos por el fichero. Ahora puedes agrupar todos los formateadores en un solo objeto, con la ventaja de que cada uno se puede sustituir, reutilizar o probar por separado.
'use strict';
const HOY = '2026-09-20';
const MESES = ['ene', 'feb', 'mar', 'abr', 'may', 'jun',
'jul', 'ago', 'sep', 'oct', 'nov', 'dic'];
const formateadores = {
// '2026-09-30' → '30 sep 2026'
fecha: (iso) => {
const [anyo, mes, dia] = [iso.slice(0, 4), iso.slice(5, 7), iso.slice(8, 10)];
return `${Number(dia)} ${MESES[Number(mes) - 1]} ${anyo}`;
},
// 'en-curso' → 'En curso'
estado: (estado) => {
if (estado === 'pendiente') return 'Pendiente';
if (estado === 'en-curso') return 'En curso';
if (estado === 'hecha') return 'Hecha';
return 'Desconocido';
},
// 'alta' → '🔴 Alta'
prioridad: (prioridad) => {
if (prioridad === 'alta') return '🔴 Alta';
if (prioridad === 'media') return '🟠 Media';
if (prioridad === 'baja') return '🟢 Baja';
return '⚪ Sin prioridad';
},
// 7.5 → '7,5 h'
horas: (horas) => `${String(horas).replace('.', ',')} h`,
// null → '—'
responsable: (nombre) => nombre ?? '—'
};
console.log(formateadores.fecha('2026-09-30')); // 30 sep 2026
console.log(formateadores.estado('en-curso')); // En curso
console.log(formateadores.prioridad('alta')); // 🔴 Alta
console.log(formateadores.horas(7.5)); // 7,5 h
console.log(formateadores.responsable(null)); // —Explicación de lo que aporta esta estructura:
- Un solo punto de cambio para toda la presentación. Si Marta pide que las fechas se muestren como
30/09/2026, tocas una línea. - Se elige el formateador con una variable.
formateadores[campo](valor)permite formatear un campo cuyo nombre no conoces hasta que se ejecuta el programa. Eso conswitchno se podía hacer. - Cada formateador es independiente. En el Módulo 8 podrás probar
formateadores.fechasin arrancar el resto de la aplicación.
Y así se usa la selección dinámica, aprovechando el ?? de Operadores Básicos:
function formatearCampo(campo, valor) {
const formateador = formateadores[campo];
if (!formateador) return String(valor); // campo sin formateador: valor crudo
return formateador(valor);
}
const campos = ['estado', 'prioridad', 'fecha', 'horas'];
const valores = ['pendiente', 'alta', '2026-09-05', 5];
for (let i = 0; i < campos.length; i++) {
console.log(`${campos[i]}: ${formatearCampo(campos[i], valores[i])}`);
}
// estado: Pendiente
// prioridad: 🔴 Alta
// fecha: 5 sep 2026
// horas: 5 hEl
const [anyo, mes, dia] = [...]del formateador de fechas es desestructuración de arrays; se estudia en Desestructuración de Arrays. Aquí solo significa "asigna el primer elemento aanyo, el segundo amesy el tercero adia".
- Una tabla de validadores recorrible
El segundo patrón que desbloquean las funciones como valores es una lista de reglas. En el Módulo 2, validar una tarea era un bloque de cuarenta líneas con if encadenados. Ahora cada regla es una entrada de un array, con su código y su mensaje:
const validadores = [
{
regla: 'R2',
mensaje: 'El título es obligatorio.',
comprobar: (titulo, horas, prioridad, fechaLimite) => titulo.trim().length > 0
},
{
regla: 'R3',
mensaje: 'Las horas deben estar entre 0 y 40.',
comprobar: (titulo, horas, prioridad, fechaLimite) => horas > 0 && horas <= 40
},
{
regla: 'R6',
mensaje: 'La prioridad debe ser alta, media o baja.',
comprobar: (titulo, horas, prioridad, fechaLimite) =>
prioridad === 'alta' || prioridad === 'media' || prioridad === 'baja'
},
{
regla: 'R4',
mensaje: 'La fecha límite no puede ser anterior a hoy.',
comprobar: (titulo, horas, prioridad, fechaLimite) => fechaLimite >= HOY
}
];
function validarTarea(titulo, horas, prioridad, fechaLimite) {
const errores = [];
for (let i = 0; i < validadores.length; i++) {
const v = validadores[i];
if (!v.comprobar(titulo, horas, prioridad, fechaLimite)) {
errores.push(`${v.regla}: ${v.mensaje}`);
}
}
return errores;
}
console.log(validarTarea('Presupuesto de la carpintería', 5, 'alta', '2026-09-05'));
// [ 'R4: La fecha límite no puede ser anterior a hoy.' ]
console.log(validarTarea(' ', 60, 'urgente', '2026-10-01'));
// [ 'R2: El título es obligatorio.',
// 'R3: Las horas deben estar entre 0 y 40.',
// 'R6: La prioridad debe ser alta, media o baja.' ]Lee bien lo que ha ocurrido aquí: añadir una regla nueva ya no significa tocar validarTarea, sino añadir un objeto al array. La función que valida no sabe cuántas reglas hay ni qué comprueban; solo sabe recorrerlas y llamarlas. Esa separación entre el motor y las reglas es una de las ideas más rentables de la programación, y en Funciones de Orden Superior la llevarás mucho más lejos.
- IIFE: la función que se llama a sí misma al nacer
Una IIFE (Immediately Invoked Function Expression, expresión de función invocada inmediatamente) es una función que se define y se ejecuta en el acto:
(function () {
const clave = 'valor privado';
console.log('Inicializando Nómada Tareas…');
})();
// Versión con flecha
(() => {
console.log('Igual, pero más corto.');
})();Los paréntesis exteriores convierten la declaración en una expresión; los () finales la llaman. Se usaban masivamente antes de 2015 por un motivo muy concreto: crear un ámbito privado. Antes de let y const, cualquier var en el fichero se volvía global y podía colisionar con otro script de la página. Envolver todo en una IIFE aislaba las variables.
// El patrón clásico de los años de jQuery
var NomadaTareas = (function () {
var contador = 0; // invisible desde fuera
return {
siguienteId: function () { return ++contador; }
};
})();
console.log(NomadaTareas.siguienteId()); // 1
console.log(NomadaTareas.siguienteId()); // 2
console.log(typeof contador); // 'undefined' → está protegido¿Sigue haciendo falta? Casi nunca. Hoy tienes dos herramientas mejores:
| Necesidad | Solución antigua | Solución moderna |
|---|---|---|
| Aislar variables de un fichero | IIFE | Módulos ES (05-04) |
| Aislar variables de un bloque | IIFE | Un bloque { } con let/const |
| Estado privado en una función | IIFE | Closures (03-04) |
Conviene reconocer el patrón porque aparece en muchísimo código heredado, pero en código nuevo lo normal es no escribirlo.
- Cuándo elegir cada forma
En la práctica profesional, la elección se reduce a estas pautas:
| Situación | Forma recomendada | Motivo |
|---|---|---|
Función principal de un fichero (validarTarea, crearTarea) |
Declaración o const + expresión |
Nombre claro en las trazas; ambas valen, elige un estilo y sé coherente |
| Callback corto de una línea | Flecha con retorno implícito | Máxima brevedad y legibilidad |
| Función guardada en un objeto de configuración | Flecha | Es un valor entre otros valores |
| Método de un objeto que usa los datos del objeto | function (o sintaxis de método) |
Necesita su propio this (ver 04-02) |
| Función recursiva | Declaración | El nombre está garantizado dentro del cuerpo |
| Manejador de evento del DOM que usa el elemento | Depende | En el Módulo 6 verás los dos casos |
Y una recomendación de estilo que siguen la mayoría de equipos: usa const + flecha por defecto, y declaración solo cuando quieras destacar una función principal del fichero. Lo importante no es cuál eliges, sino que el fichero entero sea coherente.
Errores Comunes y Consejos
1. Llamar a una expresión antes de definirla.
Con expresiones y flechas: define arriba, usa abajo. Siempre.
2. Olvidar el return al usar llaves en una flecha.
const doble = (n) => { n * 2; }; // ✗ devuelve undefined
const doble = (n) => { return n * 2; }; // ✓
const doble = (n) => n * 2; // ✓ mejor aún3. Devolver un objeto sin paréntesis. Ya lo has visto en el apartado 5: (x) => ({ ... }).
4. Olvidar el punto y coma tras una expresión de función. No suele romper nada gracias a la ASI, pero puede producir errores muy raros si la línea siguiente empieza por ( o [.
5. Usar una flecha como método que necesita this. El síntoma es un undefined inexplicable al leer una propiedad del objeto. Si te ocurre en el Módulo 4, vuelve al apartado 7.
6. Confundir funcion con funcion() al guardarla.
const formateadores = { estado: etiquetaDeEstado() }; // ✗ guarda el RESULTADO
const formateadores = { estado: etiquetaDeEstado }; // ✓ guarda la FUNCIÓNEste error es especialmente difícil de ver porque no da error de sintaxis: simplemente guardas undefined o un texto donde esperabas una función, y el fallo aparece líneas después con un TypeError: ... is not a function.
7. Consejo: si la flecha ocupa más de dos líneas, ponle llaves. El retorno implícito con expresiones larguísimas y operadores ternarios encadenados es difícil de leer y peor de depurar (no puedes poner un console.log intermedio sin reescribirla).
8. Consejo: nombra las funciones aunque sean anónimas. Asignarlas a una const con nombre descriptivo no es solo estilo: es lo que hace legibles los mensajes de error del Módulo 8.
Ejercicios
Ejercicio 1 — De declaraciones a flechas
Reescribe estas tres funciones como flechas, usando la forma más breve posible en cada caso, y comprueba que dan el mismo resultado.
function esHecha(estado) {
return estado === 'hecha';
}
function esfuerzo(prioridad, horas) {
return pesoDePrioridad(prioridad) * horas;
}
function resumenCorto(titulo, responsable, horas) {
const nombre = responsable === null ? 'sin asignar' : responsable;
return `${titulo} (${nombre}, ${horas} h)`;
}Ejercicio 2 — Tabla de comparadores
Crea un objeto comparadores cuyas claves sean 'porHoras', 'porFecha' y 'porPrioridad', y cuyos valores sean funciones que reciban los datos de dos tareas (por índice) y devuelvan -1, 0 o 1 según cuál debe ir antes. Después escribe elMasUrgente(criterio, ...) que recorra el backlog con un bucle y devuelva el índice de la tarea que queda primera según el criterio elegido. No uses sort (llega en 04-05).
Ejercicio 3 — Detectar el fallo
Cada uno de estos fragmentos tiene un error relacionado con lo estudiado en la lección. Identifícalo y corrígelo.
// a)
const etiqueta = (estado) => { estado.toUpperCase() };
console.log(etiqueta('hecha'));
// b)
const nuevaTarea = (titulo, horas) => { titulo: titulo, horas: horas };
console.log(nuevaTarea('Cartelería', 6));
// c)
console.log(pesoDe('alta'));
const pesoDe = (p) => (p === 'alta' ? 3 : 1);
// d)
const acciones = { imprimir: console.log('Hola') };
acciones.imprimir('Adiós');Soluciones
Ejercicio 1
'use strict';
const pesoDePrioridad = (prioridad) => {
if (prioridad === 'alta') return 3;
if (prioridad === 'media') return 2;
if (prioridad === 'baja') return 1;
return 0;
};
// Un parámetro, una expresión → forma mínima
const esHecha = (estado) => estado === 'hecha';
// Dos parámetros, una expresión → retorno implícito
const esfuerzo = (prioridad, horas) => pesoDePrioridad(prioridad) * horas;
// Necesita una variable intermedia → cuerpo de bloque
const resumenCorto = (titulo, responsable, horas) => {
const nombre = responsable ?? 'sin asignar';
return `${titulo} (${nombre}, ${horas} h)`;
};
console.log(esHecha('hecha')); // true
console.log(esfuerzo('alta', 12)); // 36
console.log(resumenCorto('Actualizar la web de reservas', null, 14));
// Actualizar la web de reservas (sin asignar, 14 h)Comentario: la tercera no debería escribirse con retorno implícito. Cabría en una línea usando ??, pero el bloque deja claro que hay dos pasos y permite añadir un console.log de depuración sin reescribir nada. Observa además que responsable ?? 'sin asignar' sustituye al ternario: el ?? de Operadores Básicos cubre null y undefined, que es exactamente el caso de la R8.
Ejercicio 2
const ids = [1, 2, 3, 4, 5, 6];
const prioridades = ['alta', 'media', 'alta', 'baja', 'media', 'alta'];
const horas = [12, 6, 14, 3, 8, 5];
const fechasLimite = ['2026-09-30', '2026-10-15', '2026-10-02',
'2026-09-12', '2026-11-05', '2026-09-05'];
const comparadores = {
// Más horas primero
porHoras: (a, b) => {
if (horas[a] > horas[b]) return -1;
if (horas[a] < horas[b]) return 1;
return 0;
},
// Fecha más próxima primero (las cadenas ISO se comparan directamente)
porFecha: (a, b) => {
if (fechasLimite[a] < fechasLimite[b]) return -1;
if (fechasLimite[a] > fechasLimite[b]) return 1;
return 0;
},
// Mayor peso de prioridad primero
porPrioridad: (a, b) => {
const pa = pesoDePrioridad(prioridades[a]);
const pb = pesoDePrioridad(prioridades[b]);
if (pa > pb) return -1;
if (pa < pb) return 1;
return 0;
}
};
function elMasUrgente(criterio) {
const comparar = comparadores[criterio];
if (!comparar) throw new Error(`Criterio desconocido: ${criterio}`);
let mejor = 0;
for (let i = 1; i < ids.length; i++) {
if (comparar(i, mejor) < 0) mejor = i;
}
return mejor;
}
console.log(ids[elMasUrgente('porHoras')]); // 3 (14 h)
console.log(ids[elMasUrgente('porFecha')]); // 6 (2026-09-05)
console.log(ids[elMasUrgente('porPrioridad')]); // 1 (primera 'alta' encontrada)Comentario: el patrón "máximo con bandera" es el mismo de Bucles, pero ahora el criterio de comparación entra como dato. Cambiar el orden del backlog ya no requiere reescribir el bucle. El throw para el criterio desconocido aplica el principio de fallar pronto de Manejo de Errores.
Ejercicio 3
| Fragmento | Error | Corrección |
|---|---|---|
| a) | Llaves sin return → devuelve undefined |
const etiqueta = (estado) => estado.toUpperCase(); |
| b) | Objeto literal sin paréntesis → las llaves son un bloque | const nuevaTarea = (titulo, horas) => ({ titulo, horas }); |
| c) | Expresión usada antes de definirla → ReferenceError |
Mover la definición antes de la llamada |
| d) | Se guarda el resultado de console.log('Hola') (undefined), no la función |
const acciones = { imprimir: console.log }; |
En b) aparece la abreviatura { titulo, horas }, equivalente a { titulo: titulo, horas: horas }; se estudia en Introducción a los Objetos. En d), el síntoma real es un TypeError: acciones.imprimir is not a function en la línea siguiente, lejos del error verdadero: un recordatorio de que el punto donde revienta y el punto donde está el fallo rara vez coinciden.
Conclusión
Has aprendido que en JavaScript una función es un valor de primera clase: puedes asignarla a una variable, guardarla en un array o en un objeto, compararla por referencia y pasarla como argumento. Esa propiedad, que parece un detalle técnico, es la que hace posibles los dos patrones que ya has puesto en marcha en Nómada Tareas: el objeto formateadores, que centraliza toda la presentación de campos y permite elegir el formateador con una variable, y el array validadores, que convierte cada regla de negocio en un dato y deja validarTarea completamente ajena a cuántas reglas existan.
Conoces las tres formas de escribir una función y sus diferencias reales: la declaración, disponible antes de su línea; la expresión de función, anónima o con nombre interno, que solo existe a partir de su asignación; y la función flecha, con sus variantes de cuerpo de bloque, retorno implícito, un parámetro y sin parámetros, además del truco de los paréntesis para devolver un objeto literal. Sabes que la flecha no tiene this propio ni arguments ni puede usarse con new, y que ese primer punto lo cerrarás en Métodos de Objeto y this. Y reconoces la IIFE, el patrón con el que se aislaban variables antes de que existieran let, const y los módulos.
Hay algo que se ha ido volviendo incómodo por el camino. Los validadores del apartado 9 reciben cuatro parámetros aunque cada uno use solo uno; describirTarea de la lección anterior recibía ocho; y todavía no sabes qué ocurre si alguien llama a una función con menos argumentos de los declarados, ni cómo dar un valor por defecto a revisor cuando no se indica. Todo eso —cómo entran los datos y cómo salen los resultados— es el tema de Parámetros y Valores de Retorno, donde construirás crearTarea() con valores por defecto y resumirCarga() devolviendo varios totales de una sola vez.
Curso de JavaScript: De Principiante a Avanzado
Módulo 1: Introducción a JavaScript
- ¿Qué es JavaScript?
- Configuración de tu Entorno de Desarrollo
- Tu Primer Programa en JavaScript
- Sintaxis y Conceptos Básicos de JavaScript
- Variables y Tipos de Datos
- Operadores Básicos
- Conversión de Tipos y Comparaciones
- El Proyecto del Curso: Nómada Tareas
Módulo 2: Estructuras de Control
- Sentencias Condicionales
- Bucles: for, while, do-while
- Sentencias Switch
- Control del Flujo: break, continue y Bucles Anidados
- Manejo de Errores con try-catch
Módulo 3: Funciones
- Definición y Llamada de Funciones
- Expresiones de Función y Funciones Flecha
- Parámetros y Valores de Retorno
- Ámbito y Closures
- Hoisting y el Contexto de Ejecución
- Funciones de Orden Superior
- Recursividad
Módulo 4: Objetos y Arrays
- Introducción a los Objetos
- Métodos de Objeto y la Palabra Clave
this - Arrays: Conceptos Básicos y Métodos
- Iteración sobre Arrays
- Buscar, Ordenar y Agregar Datos: find, sort y reduce
- Desestructuración de Arrays
- Desestructuración de Objetos, Spread y Rest
- JSON y Copias de Objetos
Módulo 5: Objetos y Funciones Avanzadas
- Prototipos y Herencia
- Clases y Programación Orientada a Objetos
- Encapsulación: Getters, Setters y Campos Privados
- Módulos e Importación/Exportación
- JavaScript Asíncrono: Callbacks
- Promesas y Async/Await
- El Bucle de Eventos y la Cola de Microtareas
- Iteradores y Generadores
Módulo 6: El Modelo de Objetos del Documento (DOM)
- Introducción al DOM
- Selección y Manipulación de Elementos del DOM
- Manejo de Eventos
- Propagación, Delegación y Eventos Personalizados
- Creación y Eliminación de Elementos del DOM
- Renderizado de Listas y Plantillas HTML
- Manejo y Validación de Formularios
Módulo 7: APIs del Navegador y Temas Avanzados
- Almacenamiento Local y de Sesión
- Fetch API y AJAX
- Peticiones Robustas: Errores, Timeouts y AbortController
- WebSockets
- Service Workers y Aplicaciones Web Progresivas (PWAs)
- APIs del Navegador Esenciales
- Introducción a WebAssembly
Módulo 8: Pruebas y Depuración
- Depuración de JavaScript
- Calidad de Código: ESLint, Prettier y Convenciones
- Pruebas Unitarias con Jest
- Dobles de Prueba: Mocks, Stubs y Spies
- Pruebas de Integración
- Pruebas de Extremo a Extremo con Cypress
Módulo 9: Rendimiento y Optimización
- Medir Antes de Optimizar: DevTools y Web Vitals
- Optimización del Rendimiento de JavaScript
- Gestión de Memoria
- Manipulación Eficiente del DOM
- Carga Perezosa y División de Código
Módulo 10: Frameworks y Librerías de JavaScript
- Por Qué Existen los Frameworks
- Introducción a React
- Gestión de Estado con Redux
- Conceptos Básicos de Vue.js
- Conceptos Básicos de Angular
- Elegir el Framework Adecuado
