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

  1. Las funciones son valores de primera clase
  2. La expresión de función
  3. Expresión de función con nombre
  4. La función flecha: la sintaxis completa
  5. Devolver un objeto literal desde una flecha
  6. Tabla comparativa: declaración vs expresión vs flecha
  7. La flecha y this: lo que necesitas saber hoy
  8. Un objeto de formateadores para Nómada Tareas
  9. Una tabla de validadores recorrible
  10. IIFE: la función que se llama a sí misma al nacer
  11. Cuándo elegir cada forma
  12. Errores Comunes y Consejos
  13. Ejercicios
  14. Conclusión

  1. 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.

console.log(calcularPeso === pesoDePrioridad);   // true → es el mismo objeto función

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.

  1. 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'));   // true

Tres detalles de sintaxis que conviene marcar:

  • Después de function no hay nombre. Se dice que es una función anónima.
  • La constante estaVencida es 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.

  1. 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); // ✗ ReferenceError

En 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

  1. 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:

const estaVencida = (fechaLimite, estado, hoy) => fechaLimite < hoy && estado !== 'hecha';

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:

const enMayusculas = texto => texto.toUpperCase();
const esHecha      = estado => estado === 'hecha';

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:

const fechaDeHoy = () => '2026-09-20';
console.log(fechaDeHoy());   // 2026-09-20

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

  1. 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));   // undefined

El 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"]

  1. 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ón
function f() {}
Expresión
const f = function () {}
Flecha
const 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 No: hereda el del entorno
Objeto arguments No
Se puede usar con new No (TypeError)
Retorno implícito No No Sí, si el cuerpo es una expresión
Sintaxis más breve No No
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:

  • arguments es 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.
  • new sirve para crear objetos con funciones constructoras; es materia de Prototipos y Herencia. Con una flecha da error, y eso es deliberado.
  • this merece su propio apartado.

  1. La flecha y this: lo que necesitas saber hoy

this 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:

  1. 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.
  2. Sí usa una flecha para funciones que se pasan a otra función (callbacks, manejadores de eventos del Módulo 6), porque conserva el this de 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());    // undefined

No 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.

  1. 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 con switch no se podía hacer.
  • Cada formateador es independiente. En el Módulo 8 podrás probar formateadores.fecha sin 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 h

El 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 a anyo, el segundo a mes y el tercero a dia".

  1. 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.

  1. 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.

  1. 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.

console.log(formatear('alta'));                  // ✗ ReferenceError
const formatear = (p) => p.toUpperCase();

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ún

3. 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ÓN

Este 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

Módulo 2: Estructuras de Control

Módulo 3: Funciones

Módulo 4: Objetos y Arrays

Módulo 5: Objetos y Funciones Avanzadas

Módulo 6: El Modelo de Objetos del Documento (DOM)

Módulo 7: APIs del Navegador y Temas Avanzados

Módulo 8: Pruebas y Depuración

Módulo 9: Rendimiento y Optimización

Módulo 10: Frameworks y Librerías de JavaScript

Módulo 11: Proyecto Final

© Copyright 2026. Todos los derechos reservados