Con el entorno instalado y la carpeta escena-viva/ creada, es el momento de escribir código. En esta lección construiremos el primer programa real del proyecto: src/catalogo.js, un script que define el catálogo de eventos de Escena Viva y lo muestra por consola, con la posibilidad de filtrarlo por sala desde la línea de comandos.

Por el camino descubrirás las diferencias prácticas entre ejecutar JavaScript en el navegador y en Node.js, conocerás el objeto process, aprenderás a distinguir la salida estándar de la salida de error y sabrás qué significa el código de salida de un programa. Son conceptos que parecen menores y que resultan fundamentales en cuanto tu código deja de ser un ejercicio y pasa a integrarse en un servidor o en una tubería de despliegue.

Contenido

  1. Escribir y ejecutar el primer script
  2. El navegador y Node.js: lo que hay y lo que no
  3. El objeto process: la ventana al sistema
  4. El catálogo de Escena Viva: src/catalogo.js
  5. Mostrar datos: console.log, console.table y plantillas de cadena
  6. Leer argumentos con process.argv
  7. console.error, stdout y stderr
  8. Códigos de salida y process.exit
  9. Depurar el típico error de sintaxis
  10. Qué no hace todavía este programa

  1. Escribir y ejecutar el primer script

Sitúate en la carpeta del proyecto y crea un fichero de prueba dentro de src/:

cd escena-viva

Crea src/hola.js con este contenido:

// src/hola.js
// El primer programa del curso: comprobar que Node ejecuta nuestro código.

console.log('Escena Viva: entorno operativo');
console.log('Version de Node:', process.version);
console.log('Directorio de trabajo:', process.cwd());

Ejecútalo:

node src/hola.js
Escena Viva: entorno operativo
Version de Node: v24.5.0
Directorio de trabajo: /home/usuario/proyectos/escena-viva

Tres detalles importantes de esta primera ejecución:

  • La ruta es relativa al directorio desde el que ejecutas node, no al fichero. Si estuvieras dentro de src/, el comando sería node hola.js.
  • La extensión .js es opcional: node src/hola también funciona. Escríbela siempre de todas formas; es más claro.
  • No hay compilación ni configuración previa. No hace falta package.json, ni instalar nada, ni declarar un main. Node lee el fichero y lo ejecuta.

  1. El navegador y Node.js: lo que hay y lo que no

Si vienes del desarrollo front-end, tu instinto será usar cosas que aquí no existen. Comprobémoslo:

// src/diferencias.js
// Qué objetos globales existen en Node y cuáles no.

console.log('typeof window   :', typeof window);     // undefined
console.log('typeof document :', typeof document);   // undefined
console.log('typeof alert    :', typeof alert);      // undefined
console.log('typeof global   :', typeof global);     // object
console.log('typeof process  :', typeof process);    // object
console.log('typeof console  :', typeof console);    // object
console.log('typeof fetch    :', typeof fetch);      // function
node src/diferencias.js
typeof window   : undefined
typeof document : undefined
typeof alert    : undefined
typeof global   : object
typeof process  : object
typeof console  : object
typeof fetch    : function

Resumen de equivalencias:

Tarea Navegador Node.js
Objeto global window global
Objeto global (estándar en ambos) globalThis globalThis
Mostrar información console.log, alert console.log (no hay alert)
Manipular la interfaz document.querySelector(...) No existe: no hay interfaz
Petición HTTP fetch (con restricciones CORS) fetch (sin CORS) o módulos http/https
Guardar datos localmente localStorage Ficheros (fs) o base de datos
Leer parámetros de entrada location.search process.argv
Variables de configuración Incrustadas en el bundle process.env
Terminar la ejecución Cerrar la pestaña process.exit()
Temporizadores setTimeout, setInterval Los mismos, más setImmediate

console.log funciona en ambos entornos, pero no hace lo mismo: en el navegador escribe en la consola de las herramientas de desarrollo; en Node escribe en la salida estándar del proceso, que es lo que ves en la terminal y lo que puede redirigirse a un fichero o a otro programa. Volveremos a ello en el apartado 7.

  1. El objeto process: la ventana al sistema

process es un objeto global que representa el proceso del sistema operativo en el que corre tu programa. Es la puerta de entrada a todo lo que rodea a tu código.

Propiedad o método Qué ofrece
process.argv Array con los argumentos de la línea de comandos
process.env Objeto con las variables de entorno
process.version Versión de Node (v24.5.0)
process.platform 'linux', 'darwin', 'win32'
process.cwd() Directorio de trabajo actual
process.uptime() Segundos que lleva vivo el proceso
process.memoryUsage() Uso de memoria en bytes
process.exit(codigo) Termina el proceso con un código de salida
process.exitCode Fija el código de salida sin cortar la ejecución
process.stdout / process.stderr Flujos de salida estándar y de error

Un ejemplo útil para diagnosticar entornos:

// src/entorno.js
// Diagnóstico rápido del entorno de ejecución de Escena Viva.

const memoria = process.memoryUsage();

console.log(`Node        : ${process.version}`);
console.log(`Plataforma  : ${process.platform}`);
console.log(`Directorio  : ${process.cwd()}`);
console.log(`Memoria heap: ${Math.round(memoria.heapUsed / 1024 / 1024)} MB`);
Node        : v24.5.0
Plataforma  : linux
Directorio  : /home/usuario/proyectos/escena-viva
Memoria heap: 5 MB

  1. El catálogo de Escena Viva: src/catalogo.js

Ahora el programa de verdad. Escena Viva gestiona eventos en tres salas: Teatro Almendra, Sala Bóveda y Auditorio Ribera. Cada evento tiene una o varias sesiones, y cada sesión tiene fecha, aforo, entradas vendidas y precio.

Una decisión de diseño que adoptamos desde el primer minuto: los precios se guardan en céntimos, como número entero. Nunca 25.50, siempre 2550. La razón es que el tipo number de JavaScript es de coma flotante y produce sorpresas como 0.1 + 0.2 === 0.30000000000000004. Con dinero eso es inaceptable. Formalizaremos esta y otras convenciones en El Proyecto del Curso.

Crea src/catalogo.js:

// src/catalogo.js
// Catalogo de eventos de Escena Viva.
// Por ahora los datos estan escritos en el propio fichero; en el modulo 3
// los leeremos desde datos/eventos.json.

const catalogo = [
  {
    id: 'evt-001',
    titulo: 'Concierto de Otono',
    sala: 'Teatro Almendra',
    categoria: 'concierto',
    duracionMinutos: 95,
    sesiones: [
      { id: 'ses-001-1', fechaHora: '2026-10-03T20:00:00', aforo: 420, vendidas: 180, precioCentimos: 2500 },
      { id: 'ses-001-2', fechaHora: '2026-10-04T19:00:00', aforo: 420, vendidas: 96,  precioCentimos: 2200 }
    ]
  },
  {
    id: 'evt-002',
    titulo: 'Noche de Monologos',
    sala: 'Sala Boveda',
    categoria: 'humor',
    duracionMinutos: 80,
    sesiones: [
      { id: 'ses-002-1', fechaHora: '2026-10-10T21:30:00', aforo: 120, vendidas: 118, precioCentimos: 1800 },
      { id: 'ses-002-2', fechaHora: '2026-10-11T21:30:00', aforo: 120, vendidas: 45,  precioCentimos: 1800 },
      { id: 'ses-002-3', fechaHora: '2026-10-17T21:30:00', aforo: 120, vendidas: 12,  precioCentimos: 1500 }
    ]
  },
  {
    id: 'evt-003',
    titulo: 'Festival de Jazz de Primavera',
    sala: 'Auditorio Ribera',
    categoria: 'festival',
    duracionMinutos: 240,
    sesiones: [
      { id: 'ses-003-1', fechaHora: '2027-04-17T19:00:00', aforo: 900, vendidas: 640, precioCentimos: 3800 },
      { id: 'ses-003-2', fechaHora: '2027-04-18T19:00:00', aforo: 900, vendidas: 720, precioCentimos: 4200 }
    ]
  }
];

Fíjate en un detalle deliberado: los valores de texto que van a formar parte de identificadores o de nombres de fichero evitan tildes y ñ (Concierto de Otono, Sala Boveda). En los datos que se muestran al usuario final acabaremos usando la ortografía correcta, pero mientras trabajamos por consola y con nombres técnicos, mantenerlo simple ahorra problemas de codificación. Es una convención del proyecto, no una limitación de Node.

  1. Mostrar datos: console.log, console.table y plantillas de cadena

Añade a continuación, en el mismo fichero, una función que formatee el precio y otra que imprima el catálogo.

// --- Utilidades de presentacion ---

// Convierte 2500 (centimos) en la cadena "25,00 EUR".
function formatearPrecio(centimos) {
  const euros = Math.floor(centimos / 100);
  const resto = String(centimos % 100).padStart(2, '0');
  return `${euros},${resto} EUR`;
}

// Convierte "2026-10-03T20:00:00" en "03/10/2026 20:00".
function formatearFecha(fechaISO) {
  const fecha = new Date(fechaISO);
  const dia = String(fecha.getDate()).padStart(2, '0');
  const mes = String(fecha.getMonth() + 1).padStart(2, '0');
  const anio = fecha.getFullYear();
  const hora = String(fecha.getHours()).padStart(2, '0');
  const minuto = String(fecha.getMinutes()).padStart(2, '0');
  return `${dia}/${mes}/${anio} ${hora}:${minuto}`;
}

Explicación de las piezas nuevas para quien venga con JavaScript básico:

  • Plantillas de cadena (backticks): `${euros},${resto} EUR` permite incrustar expresiones dentro de una cadena sin concatenar con +. Es más legible y admite saltos de línea reales.
  • padStart(2, '0'): rellena por la izquierda hasta alcanzar 2 caracteres. Convierte 5 en "05", que es lo que queremos en fechas y céntimos.
  • Math.floor(2500 / 100) da los euros enteros; 2500 % 100 da los céntimos sobrantes. Trabajando siempre con enteros no hay errores de redondeo.

Ahora la impresión del listado:

// --- Presentacion del catalogo ---

function mostrarCatalogo(eventos) {
  console.log('');
  console.log('==========================================');
  console.log('   ESCENA VIVA - CATALOGO DE EVENTOS');
  console.log('==========================================');

  for (const evento of eventos) {
    // Total de entradas disponibles sumando todas las sesiones.
    let disponiblesTotales = 0;
    for (const sesion of evento.sesiones) {
      disponiblesTotales += sesion.aforo - sesion.vendidas;
    }

    console.log('');
    console.log(`${evento.titulo}  [${evento.id}]`);
    console.log(`  Sala      : ${evento.sala}`);
    console.log(`  Categoria : ${evento.categoria}`);
    console.log(`  Duracion  : ${evento.duracionMinutos} min`);
    console.log(`  Sesiones  : ${evento.sesiones.length}`);
    console.log(`  Libres    : ${disponiblesTotales} entradas`);

    for (const sesion of evento.sesiones) {
      const libres = sesion.aforo - sesion.vendidas;
      const ocupacion = Math.round((sesion.vendidas / sesion.aforo) * 100);
      console.log(
        `    - ${formatearFecha(sesion.fechaHora)}  ` +
        `${formatearPrecio(sesion.precioCentimos)}  ` +
        `${libres}/${sesion.aforo} libres  (${ocupacion}% ocupado)`
      );
    }
  }

  console.log('');
}

console.table: una tabla sin esfuerzo

Node incluye console.table, que dibuja un array de objetos como tabla ASCII. Es ideal para inspeccionar datos rápidamente.

// Vista compacta en forma de tabla.
function mostrarTablaResumen(eventos) {
  // Construimos un array "plano": console.table espera objetos simples.
  const filas = eventos.map((evento) => {
    let aforoTotal = 0;
    let vendidasTotales = 0;
    for (const sesion of evento.sesiones) {
      aforoTotal += sesion.aforo;
      vendidasTotales += sesion.vendidas;
    }

    return {
      Evento: evento.titulo,
      Sala: evento.sala,
      Sesiones: evento.sesiones.length,
      Aforo: aforoTotal,
      Vendidas: vendidasTotales,
      Ocupacion: `${Math.round((vendidasTotales / aforoTotal) * 100)}%`
    };
  });

  console.table(filas);
}

Salida:

┌─────────┬────────────────────────────────┬────────────────────┬──────────┬───────┬──────────┬───────────┐
│ (index) │ Evento                         │ Sala               │ Sesiones │ Aforo │ Vendidas │ Ocupacion │
├─────────┼────────────────────────────────┼────────────────────┼──────────┼───────┼──────────┼───────────┤
│ 0       │ 'Concierto de Otono'           │ 'Teatro Almendra'  │ 2        │ 840   │ 276      │ '33%'     │
│ 1       │ 'Noche de Monologos'           │ 'Sala Boveda'      │ 3        │ 360   │ 175      │ '49%'     │
│ 2       │ 'Festival de Jazz de Primavera'│ 'Auditorio Ribera' │ 2        │ 1800  │ 1360     │ '76%'     │
└─────────┴────────────────────────────────┴────────────────────┴──────────┴───────┴──────────┴───────────┘

Otros métodos de console que conviene conocer:

Método Uso
console.log(...) Salida normal (stdout)
console.error(...) Salida de error (stderr)
console.warn(...) Igual que error: va a stderr
console.table(array) Tabla ASCII
console.dir(obj, { depth: null }) Inspecciona un objeto anidado sin recortarlo
console.time('t') / console.timeEnd('t') Mide cuánto tarda un bloque
console.count('x') Cuenta cuántas veces se pasa por un punto

  1. Leer argumentos con process.argv

Queremos poder ejecutar:

node src/catalogo.js "Sala Boveda"

y ver solo los eventos de esa sala. Los argumentos llegan en process.argv, un array de cadenas.

// Veamos primero qué contiene exactamente process.argv
console.log(process.argv);
node src/catalogo.js "Sala Boveda" --tabla
[
  '/home/usuario/.nvm/versions/node/v24.5.0/bin/node',
  '/home/usuario/proyectos/escena-viva/src/catalogo.js',
  'Sala Boveda',
  '--tabla'
]

La estructura es siempre la misma:

Índice Contenido
0 Ruta absoluta del ejecutable de Node
1 Ruta absoluta del script ejecutado
2 en adelante Los argumentos que ha escrito el usuario

De ahí el idioma habitual: process.argv.slice(2).

// --- Lectura de argumentos ---

const argumentos = process.argv.slice(2);

// El primer argumento que no empiece por "--" se interpreta como sala.
const salaFiltro = argumentos.find((arg) => !arg.startsWith('--'));
const usarTabla = argumentos.includes('--tabla');

// Filtramos el catálogo si se ha indicado una sala.
let eventosMostrados = catalogo;

if (salaFiltro) {
  eventosMostrados = catalogo.filter(
    (evento) => evento.sala.toLowerCase() === salaFiltro.toLowerCase()
  );
}

Comparar en minúsculas con toLowerCase() hace el filtro tolerante: "sala boveda" y "Sala Boveda" funcionan igual. Es un detalle pequeño con un gran efecto en la usabilidad de una herramienta de línea de comandos.

Para argumentos más complejos (opciones con valor, banderas combinadas), Node incluye util.parseArgs, y el ecosistema ofrece paquetes como commander o yargs. Los veremos cuando lleguemos a npm en el Módulo 5.

  1. console.error, stdout y stderr

Todo proceso del sistema operativo dispone de dos canales de salida separados:

  • stdout (salida estándar): el resultado útil del programa.
  • stderr (salida de error): mensajes de error, avisos y diagnósticos.

Están separados por una razón práctica: permite redirigir el resultado a un fichero sin mezclarlo con los errores.

# Solo el catálogo va al fichero; los errores siguen apareciendo en pantalla
node src/catalogo.js > informes/catalogo.txt

# Redirigir también los errores a otro fichero
node src/catalogo.js > informes/catalogo.txt 2> informes/errores.txt
flowchart LR
    P["Proceso Node<br/>src/catalogo.js"] -->|"stdout (1)<br/>console.log"| A["Terminal o<br/>informes/catalogo.txt"]
    P -->|"stderr (2)<br/>console.error"| B["Terminal o<br/>informes/errores.txt"]

Si mezclas errores en console.log, quien redirija tu salida a un fichero se encontrará mensajes de error incrustados entre los datos. Regla: los datos por console.log, todo lo demás por console.error.

Apliquémoslo al filtro por sala:

// --- Validacion del filtro ---

if (salaFiltro && eventosMostrados.length === 0) {
  // Esto es un diagnostico, no un dato: va a stderr.
  console.error(`Error: no hay eventos en la sala "${salaFiltro}".`);
  console.error('Salas disponibles:');
  for (const sala of new Set(catalogo.map((evento) => evento.sala))) {
    console.error(`  - ${sala}`);
  }
  process.exit(1);
}

new Set(...) elimina duplicados: si dos eventos comparten sala, solo aparece una vez. Lo veremos con más calma en JavaScript Moderno para Node.js.

  1. Códigos de salida y process.exit

Cuando un programa termina, devuelve al sistema operativo un número entero: el código de salida.

Código Significado convencional
0 Éxito
1 Error genérico
2 Uso incorrecto (argumentos mal escritos)
> 2 Códigos específicos que define tu aplicación

Puedes consultarlo tras ejecutar un comando:

node src/catalogo.js "Sala Inexistente"
echo $?          # Linux/macOS -> imprime 1
node src\catalogo.js "Sala Inexistente"
$LASTEXITCODE    # Windows PowerShell -> imprime 1

Esto es lo que permite encadenar comandos con seguridad en un despliegue:

# El informe solo se genera si el catálogo se validó correctamente
node src/catalogo.js --validar && node src/informe.js

process.exit() con responsabilidad

process.exit(1) corta el proceso de inmediato. Es un instrumento contundente: si hay escrituras de fichero o respuestas de red pendientes, pueden quedarse a medias.

La alternativa recomendada en la mayoría de casos es asignar process.exitCode y dejar que el programa termine de forma natural:

// Preferible: marca el código de salida pero deja terminar limpiamente
if (salaFiltro && eventosMostrados.length === 0) {
  console.error(`Error: no hay eventos en la sala "${salaFiltro}".`);
  process.exitCode = 1;
  return;   // Si estamos dentro de una función
}
Forma Cuándo usarla
process.exitCode = 1 Casi siempre: seguro, deja que se completen las tareas pendientes
process.exit(1) Errores fatales en scripts sencillos, o cuando debes cortar sin remedio

Cerramos el fichero con la ejecución:

// --- Ejecucion ---

if (usarTabla) {
  mostrarTablaResumen(eventosMostrados);
} else {
  mostrarCatalogo(eventosMostrados);
}

console.log(`Total: ${eventosMostrados.length} evento(s) mostrado(s).`);

Pruébalo:

node src/catalogo.js                       # Todo el catálogo, formato detallado
node src/catalogo.js --tabla               # Todo el catálogo, formato tabla
node src/catalogo.js "Teatro Almendra"     # Solo una sala
node src/catalogo.js "Sala Inexistente"    # Error controlado, código de salida 1

  1. Depurar el típico error de sintaxis

Introduce deliberadamente un fallo: borra una llave de cierre en el array catalogo y ejecuta el script.

/home/usuario/proyectos/escena-viva/src/catalogo.js:34
];
 ^

SyntaxError: Unexpected token ']'
    at wrapSafe (node:internal/modules/cjs/loader:1281:20)
    at Module._compile (node:internal/modules/cjs/loader:1321:27)
    ...

Node.js v24.5.0

Cómo leer este mensaje, de arriba abajo:

  1. .../src/catalogo.js:34: fichero y línea donde Node se dio cuenta del problema.
  2. El fragmento de código y el ^: el token exacto que no encajaba.
  3. SyntaxError: Unexpected token ']': el tipo de error.
  4. La pila de llamadas (at wrapSafe...): en errores de sintaxis son funciones internas de Node; ignórala, no aporta nada.

Punto clave que confunde a mucha gente: la línea que indica Node es donde el analizador se atragantó, no necesariamente donde está el fallo. Si olvidas una llave en la línea 20, el error puede señalar la 34. Busca hacia arriba desde la línea indicada.

Errores frecuentes y su mensaje:

Mensaje Causa habitual
SyntaxError: Unexpected token '}' Llave, paréntesis o corchete de más o mal cerrado
SyntaxError: Unexpected end of input Falta un cierre al final del fichero
ReferenceError: catalogo is not defined Nombre mal escrito o variable usada antes de declararla
TypeError: Cannot read properties of undefined (reading 'sesiones') Accediste a una propiedad de algo que vale undefined
Error: Cannot find module '/ruta/src/catalog.js' Nombre de fichero o ruta equivocados

Ese último es muy típico al principio: Cannot find module casi siempre significa que ejecutaste node catalogo.js desde la raíz en lugar de node src/catalogo.js.

Un editor con ESLint te habría marcado el error antes de guardar. Por eso la lección anterior insistía en configurarlo.

  1. Qué no hace todavía este programa

Es tan importante saber qué has construido como qué te falta:

Limitación actual Dónde se resuelve
Los datos están escritos dentro del .js; cambiar el catálogo obliga a tocar código Módulo 3: leeremos datos/eventos.json con fs
Solo se ve por terminal; no hay forma de consultarlo desde un navegador Módulo 4: serviremos el catálogo por HTTP
Todo el código vive en un único fichero Módulo 2: separaremos en módulos con require/module.exports
No hay persistencia de pedidos ni usuarios Módulo 7: base de datos escena_viva
El parseo de argumentos es artesanal Módulo 5: paquetes especializados

Ese es exactamente el camino del curso: el mismo src/catalogo.js irá creciendo y transformándose módulo a módulo hasta ser una API real.

Errores Comunes y Consejos

Error 1: usar window, document o alert. No existen en Node. Si un tutorial los usa, está hablando del navegador.

Error 2: creer que process.argv[0] es el primer argumento del usuario. Es la ruta del ejecutable de Node. Los argumentos del usuario empiezan en el índice 2; usa siempre process.argv.slice(2).

Error 3: mandar los errores por console.log. Contamina la salida de datos. Los errores y avisos van por console.error.

Error 4: llamar a process.exit() a mitad de una operación. Corta el proceso sin esperar a que terminen escrituras pendientes. Prefiere process.exitCode.

Error 5: ejecutar el script desde el directorio equivocado. Cannot find module suele significar eso. Comprueba process.cwd().

Error 6: buscar el error de sintaxis exactamente en la línea que indica Node. El analizador señala dónde falló, no dónde está el descuido. Mira las líneas anteriores.

Consejo 1: usa console.table para inspeccionar datos. Es mucho más legible que un console.log de un array de objetos.

Consejo 2: mide con console.time. Envolver un bloque entre console.time('carga') y console.timeEnd('carga') es la forma más barata de saber qué tarda.

Consejo 3: piensa tus scripts como comandos. Argumentos claros, datos por stdout, errores por stderr y código de salida correcto. Así podrás encadenarlos con otras herramientas.

Ejercicios

Ejercicio 1: información del entorno

Crea src/entorno.js que imprima una tabla (con console.table) con estas filas: versión de Node, plataforma, arquitectura (process.arch), directorio de trabajo, número de argumentos recibidos y memoria heap usada en MB. Ejecútalo con y sin argumentos extra y comprueba que el recuento cambia.

Ejercicio 2: filtro por precio máximo

Amplía src/catalogo.js para aceptar un segundo filtro: --max=2000 debe mostrar solo los eventos que tengan al menos una sesión cuyo precioCentimos sea menor o igual a ese valor. Requisitos:

  • Debe combinarse con el filtro de sala: node src/catalogo.js "Sala Boveda" --max=1600.
  • Si el valor de --max no es un número válido, escribe un mensaje por console.error y termina con código de salida 2.

Ejercicio 3: informe de ocupación con código de salida

Crea src/alerta-aforo.js que recorra el catálogo y liste por console.log todas las sesiones con menos del 20% de entradas vendidas (las que hay que promocionar). Reglas:

  • Formato de cada línea: evt-002 | ses-002-3 | 17/10/2026 21:30 | 10% vendido.
  • Si no hay ninguna sesión en esa situación, escribe Sin sesiones en riesgo y termina con código 0.
  • Si hay alguna, termina con código de salida 1, para que un sistema de avisos pueda detectarlo.

Soluciones

Solución 1

// src/entorno.js
// Diagnostico del entorno de ejecucion en forma de tabla.

const memoria = process.memoryUsage();
const argumentos = process.argv.slice(2);

const datos = [
  { Dato: 'Version de Node', Valor: process.version },
  { Dato: 'Plataforma',      Valor: process.platform },
  { Dato: 'Arquitectura',    Valor: process.arch },
  { Dato: 'Directorio',      Valor: process.cwd() },
  { Dato: 'Argumentos',      Valor: argumentos.length },
  { Dato: 'Heap usado (MB)', Valor: Math.round(memoria.heapUsed / 1024 / 1024) }
];

console.table(datos);
node src/entorno.js
node src/entorno.js uno dos tres    # La fila "Argumentos" pasa a valer 3

Solución 2

// --- Filtro por precio maximo ---

// Buscamos un argumento con la forma --max=NNNN
const argumentoMax = argumentos.find((arg) => arg.startsWith('--max='));

if (argumentoMax) {
  // Todo lo que hay tras el signo "=" es el valor.
  const valorTexto = argumentoMax.split('=')[1];
  const precioMaximo = Number(valorTexto);

  // Number('abc') devuelve NaN; Number('') devuelve 0, que tampoco vale aqui.
  if (!Number.isInteger(precioMaximo) || precioMaximo <= 0) {
    console.error(`Error: valor invalido en --max ("${valorTexto}").`);
    console.error('Uso: node src/catalogo.js [sala] [--max=CENTIMOS] [--tabla]');
    process.exit(2);   // 2 = uso incorrecto
  }

  eventosMostrados = eventosMostrados.filter((evento) =>
    // some() devuelve true si AL MENOS una sesion cumple la condicion.
    evento.sesiones.some((sesion) => sesion.precioCentimos <= precioMaximo)
  );
}

Este bloque debe colocarse después del filtro de sala, para que ambos se combinen: cada filtro reduce el resultado del anterior.

node src/catalogo.js --max=2000          # Noche de Monologos (1800 y 1500)
node src/catalogo.js "Sala Boveda" --max=1600   # Solo por la sesion de 1500
node src/catalogo.js --max=abc           # Error, codigo de salida 2

Solución 3

// src/alerta-aforo.js
// Lista las sesiones con baja venta para lanzar acciones de promocion.

const catalogo = require('./catalogo-datos.js'); // (ver nota al final)

const UMBRAL_PORCENTAJE = 20;
const enRiesgo = [];

for (const evento of catalogo) {
  for (const sesion of evento.sesiones) {
    const porcentaje = Math.round((sesion.vendidas / sesion.aforo) * 100);

    if (porcentaje < UMBRAL_PORCENTAJE) {
      enRiesgo.push({ evento, sesion, porcentaje });
    }
  }
}

if (enRiesgo.length === 0) {
  console.log('Sin sesiones en riesgo');
  process.exitCode = 0;
} else {
  for (const item of enRiesgo) {
    console.log(
      `${item.evento.id} | ${item.sesion.id} | ` +
      `${formatearFecha(item.sesion.fechaHora)} | ${item.porcentaje}% vendido`
    );
  }
  // Codigo distinto de 0 para que un sistema de avisos lo detecte.
  process.exitCode = 1;
}

Salida esperada con nuestros datos:

evt-002 | ses-002-3 | 17/10/2026 21:30 | 10% vendido

Nota sobre el require de la primera línea: para que este segundo script use los mismos datos habría que exportarlos desde un fichero común. Todavía no hemos visto cómo hacerlo —es el tema de Módulos CommonJS y require()—, así que de momento copia el array catalogo y la función formatearFecha dentro de src/alerta-aforo.js. Que esa duplicación te resulte incómoda es precisamente el motivo por el que existen los módulos.

Conclusión

Has escrito y ejecutado tu primer programa real en Node.js. Por el camino has visto que JavaScript en el servidor no tiene window ni document, pero sí process, el objeto que te conecta con el sistema operativo: argumentos, entorno, directorio de trabajo, memoria y código de salida.

Has construido src/catalogo.js con los tres eventos fundacionales de Escena Viva —el Concierto de Otoño en el Teatro Almendra, la Noche de Monólogos en la Sala Bóveda y el Festival de Jazz de Primavera en el Auditorio Ribera—, lo has formateado con plantillas de cadena y console.table, lo has filtrado con process.argv y has aprendido a separar los datos (stdout) de los diagnósticos (stderr), cerrando con un código de salida coherente. También sabes leer un SyntaxError sin asustarte: fichero, línea, token y a mirar hacia arriba.

Todo esto lo has hecho editando un fichero, guardándolo y volviendo a ejecutar. Existe una forma mucho más ágil de probar ideas sueltas —una expresión, una transformación del catálogo, una duda sobre cómo se comporta un método— sin ese ciclo de guardar y ejecutar. En la siguiente lección, El REPL de Node.js, aprenderás a usar el intérprete interactivo para explorar los datos de Escena Viva en vivo y probar transformaciones antes de escribirlas en el script.

Curso de Node.js: De Principiante a Avanzado

Módulo 1: Introducción a Node.js

Módulo 2: Conceptos Básicos

Módulo 3: Sistema de Archivos y E/S

Módulo 4: HTTP y Servidores Web

Módulo 5: NPM y Gestión de Paquetes

Módulo 6: Framework Express.js

Módulo 7: Bases de Datos y ORMs

Módulo 8: Autenticación y Autorización

Módulo 9: Pruebas y Depuración

Módulo 10: Temas Avanzados

Módulo 11: Despliegue y DevOps

Módulo 12: Proyectos del Mundo Real

© Copyright 2026. Todos los derechos reservados