En la lección anterior seguiste un ciclo que conoces bien: escribir código, guardar, ejecutar node src/catalogo.js, leer la salida, corregir, repetir. Ese ciclo es correcto para construir un programa, pero es lentísimo cuando lo que quieres es responder a una pregunta pequeña: ¿cómo se comporta reduce con este array?, ¿qué devuelve exactamente Object.entries sobre una sesión?, ¿cuánto suma el aforo total del Auditorio Ribera?
Para eso existe el REPL: un intérprete interactivo donde escribes una expresión y ves el resultado al instante. Es una de las herramientas más infravaloradas del ecosistema y, bien usada, ahorra horas. En esta lección aprenderás a manejarlo con soltura y a explorar en vivo los datos de Escena Viva antes de escribirlos en un script.
Contenido
- Qué es un REPL y para qué sirve
- Arrancar el REPL y evaluar expresiones
- La variable
_y el resultado de las declaraciones - Autocompletado, historial y navegación
- Los comandos de punto
- Cargar el catálogo de Escena Viva en el REPL
- Explorar y transformar los datos en vivo
- El modo
.editorpara funciones de varias líneas - Ejecutar código suelto sin REPL:
node -eynode -p - Peculiaridades: promesas,
awaitde nivel superior y otras sorpresas - Cuándo usar el REPL y cuándo no
- Qué es un REPL y para qué sirve
REPL son las siglas de Read-Eval-Print-Loop: leer, evaluar, imprimir y repetir. Es un bucle que:
- Lee (Read) lo que escribes.
- Lo evalúa (Eval) como código JavaScript.
- Imprime (Print) el resultado.
- Repite (Loop) esperando la siguiente línea.
flowchart LR
R["Read<br/>lee tu línea"] --> E["Eval<br/>ejecuta el código"]
E --> P["Print<br/>muestra el resultado"]
P --> L["Loop<br/>espera la siguiente"]
L --> R
No es una peculiaridad de Node: la consola del navegador es un REPL, y también lo son python, irb o psql. Su valor está en el coste cero del experimento: probar algo no requiere crear ficheros ni recordar rutas.
Usos reales en el día a día:
- Comprobar el comportamiento exacto de un método de array que no usas a menudo.
- Verificar una expresión regular antes de meterla en el código.
- Explorar la forma de unos datos que acabas de recibir.
- Convertir valores rápidamente (fechas, céntimos a euros, bytes a megabytes).
- Comprobar qué exporta un módulo instalado, sin leer su documentación.
- Arrancar el REPL y evaluar expresiones
Escribe node sin argumentos:
El símbolo > indica que el REPL espera una línea. Prueba:
> 2 + 2 4 > 'Teatro' + ' ' + 'Almendra' 'Teatro Almendra' > [1, 2, 3].map((n) => n * 10) [ 10, 20, 30 ] > Math.round(2500 / 100) 25
El REPL mantiene el estado entre líneas: las variables que declaras siguen existiendo.
> const sala = 'Auditorio Ribera' undefined > sala.toUpperCase() 'AUDITORIO RIBERA' > sala.length 16
También funciona con código de varias líneas: si una línea está incompleta, el símbolo cambia a ... y el REPL espera a que cierres.
> const sesion = {
... id: 'ses-001-1',
... aforo: 420,
... vendidas: 180
... }
undefined
> sesion.aforo - sesion.vendidas
240Para salir: .exit, o Ctrl+D, o Ctrl+C dos veces.
- La variable
_ y el resultado de las declaraciones
_ y el resultado de las declaracionesEl resultado undefined de las declaraciones
Habrás notado algo desconcertante: al escribir const sala = 'Auditorio Ribera' el REPL respondió undefined. No es un error. El REPL imprime el valor de la expresión evaluada, y en JavaScript una declaración de variable no produce ningún valor: produce undefined.
> const precio = 2500 undefined > precio // Ahora sí, esto es una expresión que vale 2500 2500 > let x = 10; x // Truco: separar con ";" para ver el valor 10
Lo mismo ocurre con function, class, bucles y console.log (que devuelve undefined después de imprimir):
La primera línea es lo que imprime console.log; la segunda es su valor de retorno. Con el tiempo dejas de verlo.
La variable _
_ guarda el resultado de la última expresión evaluada. Es comodísimo para encadenar exploraciones sin declarar variables intermedias.
Hay una variable hermana, _error, que guarda el último error lanzado:
> JSON.parse('{ esto no es json }')
Uncaught SyntaxError: Expected property name or '}' in JSON at position 2
> _error.message
"Expected property name or '}' in JSON at position 2"Cuidado: si asignas manualmente
_ = 5, pierdes esta funcionalidad en esa sesión (el REPL te avisa). Evita usar_como nombre de variable propia.
- Autocompletado, historial y navegación
Estas teclas convierten el REPL en algo verdaderamente rápido:
| Tecla | Efecto |
|---|---|
Tab |
Autocompleta. Si hay varias opciones, pulsa dos veces para listarlas |
↑ / ↓ |
Recorre el historial de comandos |
Ctrl+R |
Búsqueda inversa en el historial (escribe parte del comando) |
Ctrl+A / Ctrl+E |
Ir al principio / final de la línea |
Ctrl+U |
Borrar la línea entera |
Ctrl+L |
Limpiar la pantalla |
Ctrl+C |
Cancelar la línea actual (dos veces: salir) |
Ctrl+D |
Salir |
El autocompletado es la joya. Escribe un objeto y un punto, y pulsa Tab:
> const sesion = { id: 'ses-001-1', aforo: 420, vendidas: 180 }
undefined
> sesion.
sesion.__proto__ sesion.constructor sesion.hasOwnProperty
...
sesion.aforo sesion.id sesion.vendidasTambién funciona con módulos internos, lo que lo convierte en una documentación instantánea:
> const path = require('node:path')
undefined
> path.
path.basename path.dirname path.extname path.join
path.normalize path.parse path.relative path.resolveEl historial se conserva entre sesiones en el fichero ~/.node_repl_history. Puedes cerrar el REPL, abrirlo mañana y recuperar con ↑ lo que probaste hoy.
- Los comandos de punto
Todo lo que empieza por . en el REPL es una orden del propio REPL, no JavaScript.
| Comando | Qué hace |
|---|---|
.help |
Lista todos los comandos disponibles |
.break |
Abandona una expresión multilínea a medias (alias: Ctrl+C) |
.clear |
Reinicia el contexto: borra todas tus variables |
.editor |
Entra en modo editor multilínea |
.exit |
Sale del REPL |
.load <fichero> |
Carga y evalúa un fichero en la sesión actual |
.save <fichero> |
Guarda en un fichero todo lo que has escrito en la sesión |
Ejemplo del ciclo completo .load / .save:
.save escribe todas las líneas que has tecleado (no los resultados). Es una forma cómoda de rescatar una exploración que ha salido bien y convertirla en el punto de partida de un script.
.break te salva del atasco clásico:
Sin .break (o Ctrl+C), el REPL se queda esperando eternamente el cierre de la llave.
.clear merece un aviso: reinicia el contexto y pierdes todas las variables definidas. Úsalo cuando quieras empezar de cero, no por error.
- Cargar el catálogo de Escena Viva en el REPL
Aquí está la aplicación práctica de .load. Vamos a preparar un fichero que contenga solo los datos, sin la parte de presentación ni el filtrado por argumentos, para poder cargarlo limpiamente en el REPL.
Crea src/catalogo-datos.js:
// src/catalogo-datos.js
// Solo los datos del catalogo, sin logica de presentacion.
// En el modulo 2 anadiremos aqui module.exports para poder reutilizarlo
// desde otros ficheros; de momento sirve para cargarlo en el REPL con .load
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 }
]
}
];Ahora, desde la raíz del proyecto:
El REPL muestra el contenido del fichero mientras lo evalúa línea a línea. Al terminar, la constante catalogo existe en tu sesión:
Punto importante:
.loadno es lo mismo querequire..loadcopia y evalúa el texto del fichero dentro del contexto del REPL, como si lo hubieras tecleado.requirecarga un módulo aislado y solo te da lo que ese módulo exporta. Por eso.loadfunciona aunque el fichero no exporte nada, y por eso es la herramienta ideal para explorar. Los módulos de verdad llegan en el Módulo 2.
- Explorar y transformar los datos en vivo
Con el catálogo cargado, empieza lo divertido: probar transformaciones antes de escribirlas en el script.
Ver la forma de los datos
> catalogo.map((e) => e.titulo) [ 'Concierto de Otono', 'Noche de Monologos', 'Festival de Jazz de Primavera' ] > catalogo[1].sesiones.length 3
Para inspeccionar un objeto anidado sin que Node lo recorte con [Object]:
filter: quedarse con parte del catálogo
> catalogo.filter((e) => e.sala === 'Sala Boveda').map((e) => e.titulo) [ 'Noche de Monologos' ] > catalogo.filter((e) => e.duracionMinutos > 90).map((e) => e.titulo) [ 'Concierto de Otono', 'Festival de Jazz de Primavera' ]
flatMap: aplanar todas las sesiones
Las sesiones están anidadas dentro de cada evento. Para trabajar con todas a la vez:
Y si necesitamos saber a qué evento pertenece cada una, añadimos el dato al aplanar:
> const sesiones = catalogo.flatMap((e) => e.sesiones.map((s) => ({ ...s, evento: e.titulo, sala: e.sala })))
undefined
> sesiones[0]
{
id: 'ses-001-1',
fechaHora: '2026-10-03T20:00:00',
aforo: 420,
vendidas: 180,
precioCentimos: 2500,
evento: 'Concierto de Otono',
sala: 'Teatro Almendra'
}El operador ... (propagación) copia todas las propiedades del objeto original y añade las nuevas. Lo estudiaremos formalmente en la siguiente lección.
reduce: totales de negocio
> sesiones.reduce((suma, s) => suma + s.aforo, 0) 3000 > sesiones.reduce((suma, s) => suma + s.vendidas, 0) 1811 > const ingresos = sesiones.reduce((suma, s) => suma + s.vendidas * s.precioCentimos, 0) undefined > ingresos 6428600 > ingresos / 100 64286
Sesenta y cuatro mil doscientos ochenta y seis euros de recaudación acumulada. Este es exactamente el tipo de pregunta que respondes en veinte segundos en el REPL y que tardarías cinco minutos en programar, guardar y ejecutar.
sort y find
> sesiones.filter((s) => s.sala === 'Auditorio Ribera').map((s) => s.id)
[ 'ses-003-1', 'ses-003-2' ]
> [...sesiones].sort((a, b) => b.precioCentimos - a.precioCentimos)[0].id
'ses-003-2'
> sesiones.find((s) => s.vendidas / s.aforo < 0.2)
{ id: 'ses-002-3', ... }Nota el [...sesiones] antes de sort: sort modifica el array original. Copiarlo primero evita alterar los datos que estás explorando. Es un error clásico que el REPL te ayuda a descubrir.
Ocupación por sala
> const porSala = {}
undefined
> for (const s of sesiones) { porSala[s.sala] = (porSala[s.sala] ?? 0) + s.vendidas }
undefined
> porSala
{ 'Teatro Almendra': 276, 'Sala Boveda': 175, 'Auditorio Ribera': 1360 }
> console.table(porSala)El operador ?? devuelve el valor de la derecha solo si el de la izquierda es null o undefined. Lo veremos en detalle en la próxima lección.
- El modo
.editor para funciones de varias líneas
.editor para funciones de varias líneasEscribir una función de diez líneas en el REPL línea a línea es incómodo: si te equivocas en la tercera, no puedes volver atrás. Para eso está .editor.
> .editor
// Entering editor mode (Ctrl+D to finish, Ctrl+C to cancel)
function resumenSala(eventos, sala) {
const sesiones = eventos
.filter((evento) => evento.sala === sala)
.flatMap((evento) => evento.sesiones);
const aforo = sesiones.reduce((total, s) => total + s.aforo, 0);
const vendidas = sesiones.reduce((total, s) => total + s.vendidas, 0);
return {
sala,
sesiones: sesiones.length,
aforo,
vendidas,
ocupacion: `${Math.round((vendidas / aforo) * 100)}%`
};
}Pulsa Ctrl+D para salir del modo editor y evaluar todo el bloque de golpe. Luego pruébala:
> resumenSala(catalogo, 'Teatro Almendra')
{ sala: 'Teatro Almendra', sesiones: 2, aforo: 840, vendidas: 276, ocupacion: '33%' }
> ['Teatro Almendra', 'Sala Boveda', 'Auditorio Ribera'].map((s) => resumenSala(catalogo, s))> console.table(['Teatro Almendra', 'Sala Boveda', 'Auditorio Ribera'].map((s) => resumenSala(catalogo, s))) ┌─────────┬────────────────────┬──────────┬───────┬──────────┬───────────┐ │ (index) │ sala │ sesiones │ aforo │ vendidas │ ocupacion │ ├─────────┼────────────────────┼──────────┼───────┼──────────┼───────────┤ │ 0 │ 'Teatro Almendra' │ 2 │ 840 │ 276 │ '33%' │ │ 1 │ 'Sala Boveda' │ 3 │ 360 │ 175 │ '49%' │ │ 2 │ 'Auditorio Ribera' │ 2 │ 1800 │ 1360 │ '76%' │ └─────────┴────────────────────┴──────────┴───────┴──────────┴───────────┘
Cuando la función funciona, .save informes/exploracion.js guarda la sesión y ya tienes el código listo para pegarlo en src/.
Ctrl+Dtermina,Ctrl+Ccancela. Confundirlos hace perder el bloque entero. En Windows, siCtrl+Dno responde, prueba conCtrl+Zseguido deEnter.
- Ejecutar código suelto sin REPL:
node -e y node -p
node -e y node -pA veces solo quieres una respuesta y no una sesión interactiva. Node acepta código directamente desde la línea de comandos.
| Opción | Significado | Imprime el resultado |
|---|---|---|
node -e "código" |
evaluate: ejecuta el código | No (usa console.log) |
node -p "código" |
print: ejecuta e imprime el valor | Sí, automáticamente |
# -e: hay que imprimir explícitamente
node -e "console.log(2 + 2)"
# 4
# -p: imprime el valor de la expresión
node -p "2 + 2"
# 4
# Consultar la versión desde un script de despliegue
node -p "process.version"
# v24.5.0
# Comprobar si un paquete está instalado y qué versión tiene
node -p "require('express/package.json').version"Un caso muy práctico: procesar un fichero JSON desde la terminal sin instalar herramientas adicionales.
# Cuántos eventos hay en el fichero semilla
node -p "require('./datos/eventos.json').length"
# Títulos de los eventos, uno por línea
node -e "require('./datos/eventos.json').forEach(e => console.log(e.titulo))"Node sabe leer un .json con require y devolverlo ya convertido en objeto. Este truco te resolverá muchas comprobaciones rápidas a partir del Módulo 3, cuando el fichero datos/eventos.json sea la fuente real del catálogo.
También puedes encadenar el REPL con una tubería, aunque en ese caso no verás el símbolo >:
- Peculiaridades: promesas,
await de nivel superior y otras sorpresas
await de nivel superior y otras sorpresasPromesas y await
El REPL de Node soporta await en el nivel superior, algo que en un fichero .js de tipo CommonJS no se puede hacer. Esto lo convierte en un banco de pruebas excelente para código asíncrono (tema del Módulo 2).
> const fs = require('node:fs/promises')
undefined
> const texto = await fs.readFile('src/catalogo-datos.js', 'utf8')
undefined
> texto.length
1893Si no usas await, el REPL te muestra la promesa, no su valor:
Poco después el REPL imprime el resultado resuelto por su cuenta, lo que puede parecer que "aparece de la nada". No te alarmes: es el REPL informando de que la promesa se ha resuelto.
Otras peculiaridades que conviene conocer
| Situación | Qué ocurre | Por qué |
|---|---|---|
{ a: 1 } devuelve 1 |
El REPL interpreta {} como un bloque, no como un objeto |
Envuélvelo en paréntesis: ({ a: 1 }) |
let x = 1 dos veces da error |
Redeclaración en el mismo ámbito | Usa var, o .clear, o cambia de nombre |
Un array largo se recorta con ... 73 more items |
Límite de impresión del inspector | console.dir(arr, { maxArrayLength: null }) |
Objetos profundos muestran [Object] |
Profundidad de inspección por defecto: 2 | console.dir(obj, { depth: null }) |
El REPL no ve las variables de un fichero cargado con require |
require aísla el módulo |
Usa .load para explorar |
| Un error no cierra el REPL | Los errores se capturan y se muestran | Es intencionado: puedes seguir trabajando |
Prueba tú mismo la primera:
> { titulo: 'Concierto de Otono' }
'Concierto de Otono'
> ({ titulo: 'Concierto de Otono' })
{ titulo: 'Concierto de Otono' }En el primer caso, JavaScript lee { como inicio de bloque y titulo: como una etiqueta; el valor del bloque es la última expresión. Con paréntesis, se fuerza la interpretación como objeto literal.
- Cuándo usar el REPL y cuándo no
El REPL es una herramienta de exploración, no de construcción. Esta tabla resume la elección correcta:
| Necesidad | Herramienta adecuada |
|---|---|
| Comprobar qué devuelve una expresión | REPL |
| Explorar la forma de unos datos desconocidos | REPL (.load + console.dir) |
| Probar una transformación antes de escribirla | REPL o .editor |
| Consultar la API de un módulo | REPL + Tab |
| Una comprobación puntual desde un script de shell | node -p |
| Código que debe repetirse o versionarse | Un fichero en src/ |
| Lógica de más de 30 líneas | Un fichero, aunque la hayas prototipado en el REPL |
| Entender por qué falla un programa complejo en un punto concreto | El depurador (Módulo 9) |
| Garantizar que algo sigue funcionando mañana | Pruebas automatizadas (Módulo 9) |
La regla es sencilla: si vas a necesitar el resultado más de una vez, no pertenece al REPL. Prototipa en el REPL, guarda con .save, refina en un fichero.
Y sobre el depurador: el REPL te dice qué hace una expresión aislada; el depurador te deja detener un programa en marcha, en la línea que quieras, e inspeccionar todas sus variables en ese instante. Son complementarios, no alternativos.
Errores Comunes y Consejos
Error 1: alarmarse por el undefined tras cada declaración.
Es el valor de la expresión, no un fallo. const x = 5 no produce ningún valor.
Error 2: escribir { clave: valor } esperando un objeto.
El REPL lo lee como un bloque. Envuélvelo en paréntesis.
Error 3: quedarse atrapado en el símbolo ....
Has dejado una llave, un paréntesis o una comilla sin cerrar. Sal con .break o Ctrl+C.
Error 4: confundir .load con require.
.load evalúa el texto en tu sesión (ves todas las variables). require devuelve solo lo exportado.
Error 5: usar .clear sin querer.
Borra todas las variables de la sesión. Si has invertido tiempo en cargar y transformar datos, primero .save.
Error 6: ordenar con sort y estropear el array original.
sort, reverse, splice, push y pop modifican el array. Copia con [...array] antes de ordenar.
Consejo 1: usa _ sin miedo. Encadenar _ es la forma más rápida de refinar un cálculo paso a paso.
Consejo 2: .save al terminar una exploración productiva. Guardar en informes/ la sesión te evita reconstruir el razonamiento mañana.
Consejo 3: el Tab es tu documentación. Antes de buscar en internet qué métodos tiene path, escribe path. y pulsa Tab dos veces.
Consejo 4: mantén un REPL abierto en una pestaña de la terminal. Con el catálogo cargado, resolver dudas cuesta segundos.
Ejercicios
Ejercicio 1: exploración guiada del catálogo
Abre el REPL, carga src/catalogo-datos.js con .load y responde a estas preguntas usando una sola expresión cada vez. Anota el comando y el resultado.
- ¿Cuántas sesiones hay en total en el catálogo?
- ¿Cuál es el precio medio de una entrada, en euros?
- ¿Qué eventos tienen más de dos sesiones?
- ¿Cuántas entradas quedan sin vender en todo el catálogo?
- ¿Cuál es la sesión más cara y a qué evento pertenece?
Ejercicio 2: función en modo editor
Usando .editor, escribe una función sesionesPorMes(eventos) que devuelva un objeto donde cada clave sea el mes en formato AAAA-MM y el valor el número de sesiones programadas ese mes. Pruébala con el catálogo y muestra el resultado con console.table. Después guarda la sesión en informes/exploracion-meses.js con .save.
Pista: sesion.fechaHora es una cadena ISO como '2026-10-03T20:00:00', así que el mes se puede extraer con slice(0, 7).
Ejercicio 3: comprobaciones desde la terminal
Sin abrir el REPL, escribe los comandos node -e o node -p que resuelvan lo siguiente:
- Imprimir la versión mayor de Node instalada (solo el número, por ejemplo
24). - Imprimir cuántos milisegundos faltan desde ahora hasta el
Concierto de Otono(2026-10-03T20:00:00). - Convertir
4200céntimos a la cadena'42.00'. - Comprobar si la carpeta
informesexiste en el proyecto (imprimirtrueofalse).
Soluciones
Solución 1
> .load src/catalogo-datos.js # 1. Total de sesiones > catalogo.reduce((total, e) => total + e.sesiones.length, 0) 7 # 2. Precio medio en euros > catalogo.flatMap(e => e.sesiones).reduce((s, x, i, a) => s + x.precioCentimos / a.length, 0) / 100 25.428571428571427
Alternativa más legible, en dos pasos con _:
> catalogo.flatMap(e => e.sesiones).map(s => s.precioCentimos) [ 2500, 2200, 1800, 1800, 1500, 3800, 4200 ] > _.reduce((a, b) => a + b, 0) / _.length / 100 25.428571428571427
(17.800 céntimos entre 7 sesiones = 2.542,86 céntimos, es decir 25,43 EUR.)
# 3. Eventos con mas de dos sesiones
> catalogo.filter(e => e.sesiones.length > 2).map(e => e.titulo)
[ 'Noche de Monologos' ]
# 4. Entradas sin vender
> catalogo.flatMap(e => e.sesiones).reduce((t, s) => t + (s.aforo - s.vendidas), 0)
1189
# 5. Sesion mas cara y su evento
> catalogo.flatMap(e => e.sesiones.map(s => ({ ...s, evento: e.titulo })))
.sort((a, b) => b.precioCentimos - a.precioCentimos)[0]
{ id: 'ses-003-2', ..., precioCentimos: 4200, evento: 'Festival de Jazz de Primavera' }Aquí sort sobre el resultado de flatMap es seguro: ese array es nuevo, no el original.
Solución 2
> .editor
function sesionesPorMes(eventos) {
const conteo = {};
for (const evento of eventos) {
for (const sesion of evento.sesiones) {
// '2026-10-03T20:00:00'.slice(0, 7) === '2026-10'
const mes = sesion.fechaHora.slice(0, 7);
conteo[mes] = (conteo[mes] ?? 0) + 1;
}
}
return conteo;
}Ctrl+D y a probar:
> sesionesPorMes(catalogo)
{ '2026-10': 5, '2027-04': 2 }
> console.table(sesionesPorMes(catalogo))
┌─────────┬────────┐
│ (index) │ Values │
├─────────┼────────┤
│ 2026-10 │ 5 │
│ 2027-04 │ 2 │
└─────────┴────────┘
> .save informes/exploracion-meses.js
Session saved to: informes/exploracion-meses.jsTen en cuenta que .save guarda toda la sesión, incluidas las líneas fallidas. Revisa el fichero antes de reutilizarlo.
Solución 3
# 1. Version mayor de Node
node -p "process.versions.node.split('.')[0]"
# 24
# 2. Milisegundos hasta el Concierto de Otono
node -p "new Date('2026-10-03T20:00:00') - new Date()"
# 4483200000 (varía según cuándo lo ejecutes)
# 3. Centimos a cadena con dos decimales
node -p "(4200 / 100).toFixed(2)"
# 42.00
# 4. Comprobar si existe la carpeta informes
node -p "require('node:fs').existsSync('informes')"
# trueEn el punto 2, restar dos objetos Date los convierte automáticamente a milisegundos desde época y devuelve la diferencia. Si prefieres días:
Conclusión
El REPL es el laboratorio de Node.js: un entorno donde probar ideas cuesta cero. Has aprendido a arrancarlo con node, a interpretar el undefined de las declaraciones, a encadenar cálculos con _, a moverte con Tab y el historial, y a manejar los comandos de punto —.help, .editor, .save, .load, .break, .clear, .exit—.
Lo has aplicado a Escena Viva creando src/catalogo-datos.js y cargándolo con .load para explorar en vivo: aplanar sesiones con flatMap, calcular la recaudación acumulada con reduce, detectar la sesión más cara con sort o descubrir que hay 1.189 entradas por vender. También has visto node -e y node -p para comprobaciones desde la terminal, y las peculiaridades que confunden al principio: los objetos literales que necesitan paréntesis, las promesas pendientes y el await de nivel superior.
Y sobre todo tienes claro el límite: el REPL sirve para explorar; lo que debe repetirse va a un fichero, y lo que debe garantizarse va a un test.
En esa exploración han aparecido, casi de contrabando, herramientas del JavaScript moderno: flatMap, el operador de propagación ..., la coalescencia nula ??, las funciones flecha y la desestructuración. En la siguiente lección, JavaScript Moderno para Node.js, las estudiaremos una por una y con calma, siempre resolviendo un problema real del catálogo de Escena Viva. Es el repaso que sostendrá todo el código que escribas de aquí al final del curso.
Curso de Node.js: De Principiante a Avanzado
Módulo 1: Introducción a Node.js
- ¿Qué es Node.js?
- Instalación y Configuración del Entorno
- Tu Primer Programa en Node.js
- El REPL de Node.js
- JavaScript Moderno para Node.js
- El Proyecto del Curso: la Plataforma Escena Viva
Módulo 2: Conceptos Básicos
- Arquitectura de Node.js
- El Bucle de Eventos (Event Loop)
- Callbacks y Programación Asíncrona
- Promesas y async/await
- Eventos y EventEmitter
- Módulos CommonJS y require()
- Módulos ES e Interoperabilidad
Módulo 3: Sistema de Archivos y E/S
- Lectura y Escritura de Archivos
- El Módulo fs a Fondo
- Rutas Multiplataforma con el Módulo path
- Trabajando con Streams
- Streams de Transformación y pipeline
- Buffers y Datos Binarios
Módulo 4: HTTP y Servidores Web
- Creando un Servidor HTTP Simple
- Manejo de Solicitudes y Respuestas
- Enrutamiento Manual
- Sirviendo Archivos Estáticos
- Recibiendo Datos: Cuerpos de Petición y JSON
- Consumiendo APIs Externas desde Node.js
Módulo 5: NPM y Gestión de Paquetes
- Introducción a NPM y package.json
- Instalación y Uso de Paquetes
- Versionado Semántico y package-lock
- Scripts de npm y Automatización del Proyecto
- Creación y Publicación de Paquetes
- Seguridad y Mantenimiento de Dependencias
Módulo 6: Framework Express.js
- Introducción a Express.js
- Configuración de una Aplicación Express
- Enrutamiento en Express
- Middleware
- Middleware de Terceros Esenciales
- Validación de Datos de Entrada
- Manejo de Errores
Módulo 7: Bases de Datos y ORMs
- Introducción a las Bases de Datos
- Usando MongoDB con Mongoose
- Operaciones CRUD
- Relaciones, Poblado y Consultas Avanzadas
- Usando Bases de Datos SQL con Sequelize
- Migraciones, Transacciones y Datos de Prueba
Módulo 8: Autenticación y Autorización
- Introducción a la Autenticación
- Registro de Usuarios y Hash de Contraseñas
- Sesiones y Cookies con Passport.js
- Autenticación con JWT
- Control de Acceso Basado en Roles
- Buenas Prácticas de Seguridad en APIs
Módulo 9: Pruebas y Depuración
- Introducción a las Pruebas
- Pruebas Unitarias con Mocha y Chai
- Dobles de Prueba con Sinon
- Pruebas de Integración
- Cobertura y Automatización de las Pruebas
- Depuración de Aplicaciones Node.js
Módulo 10: Temas Avanzados
- El Módulo Cluster
- Hilos de Trabajo (Worker Threads)
- Caché y Colas de Trabajo con Redis
- Optimización del Rendimiento
- Construcción de APIs RESTful
- GraphQL con Node.js
Módulo 11: Despliegue y DevOps
- Configuración y Variables de Entorno
- Registro y Monitorización en Producción
- Usando PM2 para la Gestión de Procesos
- Empaquetado con Docker
- Desplegando en Heroku y Otras PaaS
- Integración y Despliegue Continuos
