A la lliçó anterior vas seguir un cicle que coneixes bé: escriure codi, desar, executar node src/cataleg.js, llegir la sortida, corregir, repetir. Aquest cicle és correcte per construir un programa, però és lentíssim quan el que vols és respondre una pregunta petita: com es comporta reduce amb aquest array?, què retorna exactament Object.entries sobre una sessió?, quant suma l'aforament total de l'Auditorio Ribera?

Per a això existeix el REPL: un intèrpret interactiu on escrius una expressió i en veus el resultat a l'instant. És una de les eines més infravalorades de l'ecosistema i, ben feta servir, estalvia hores. En aquesta lliçó aprendràs a manejar-lo amb solvència i a explorar en directe les dades d'Escena Viva abans d'escriure-les en un script.

Contingut

  1. Què és un REPL i per a què serveix
  2. Arrencar el REPL i avaluar expressions
  3. La variable _ i el resultat de les declaracions
  4. Autocompletat, historial i navegació
  5. Les ordres de punt
  6. Carregar el catàleg d'Escena Viva al REPL
  7. Explorar i transformar les dades en directe
  8. El mode .editor per a funcions de diverses línies
  9. Executar codi solt sense REPL: node -e i node -p
  10. Peculiaritats: promeses, await de nivell superior i altres sorpreses
  11. Quan fer servir el REPL i quan no

  1. Què és un REPL i per a què serveix

REPL són les sigles de Read-Eval-Print-Loop: llegir, avaluar, imprimir i repetir. És un bucle que:

  1. Llegeix (Read) el que escrius.
  2. Ho avalua (Eval) com a codi JavaScript.
  3. Imprimeix (Print) el resultat.
  4. Repeteix (Loop) esperant la línia següent.
flowchart LR
    R["Read<br/>llegeix la teva línia"] --> E["Eval<br/>executa el codi"]
    E --> P["Print<br/>mostra el resultat"]
    P --> L["Loop<br/>espera la següent"]
    L --> R

No és una peculiaritat de Node: la consola del navegador és un REPL, i també ho són python, irb o psql. El seu valor és el cost zero de l'experiment: provar una cosa no requereix crear fitxers ni recordar rutes.

Usos reals del dia a dia:

  • Comprovar el comportament exacte d'un mètode d'array que no fas servir sovint.
  • Verificar una expressió regular abans de ficar-la al codi.
  • Explorar la forma d'unes dades que acabes de rebre.
  • Convertir valors ràpidament (dates, cèntims a euros, bytes a megabytes).
  • Comprovar què exporta un mòdul instal·lat, sense llegir-ne la documentació.

  1. Arrencar el REPL i avaluar expressions

Escriu node sense arguments:

node
Welcome to Node.js v24.5.0.
Type ".help" for more information.
>

El símbol > indica que el REPL espera una línia. Prova:

> 2 + 2
4
> 'Teatro' + ' ' + 'Almendra'
'Teatro Almendra'
> [1, 2, 3].map((n) => n * 10)
[ 10, 20, 30 ]
> Math.round(2500 / 100)
25

El REPL manté l'estat entre línies: les variables que declares continuen existint.

> const sala = 'Auditorio Ribera'
undefined
> sala.toUpperCase()
'AUDITORIO RIBERA'
> sala.length
16

També funciona amb codi de diverses línies: si una línia està incompleta, el símbol canvia a ... i el REPL espera que tanquis.

> const sessio = {
...   id: 'ses-001-1',
...   aforament: 420,
...   venudes: 180
... }
undefined
> sessio.aforament - sessio.venudes
240

Per sortir: .exit, o Ctrl+D, o Ctrl+C dues vegades.

  1. La variable _ i el resultat de les declaracions

El resultat undefined de les declaracions

Deus haver notat una cosa desconcertant: en escriure const sala = 'Auditorio Ribera' el REPL ha respost undefined. No és un error. El REPL imprimeix el valor de l'expressió avaluada, i en JavaScript una declaració de variable no produeix cap valor: produeix undefined.

> const preu = 2500
undefined
> preu            // Ara si, aixo es una expressio que val 2500
2500
> let x = 10; x   // Truc: separar amb ";" per veure el valor
10

El mateix passa amb function, class, bucles i console.log (que retorna undefined després d'imprimir):

> console.log('hola')
hola
undefined

La primera línia és el que imprimeix console.log; la segona és el seu valor de retorn. Amb el temps deixes de veure-ho.

La variable _

_ guarda el resultat de l'última expressió avaluada. És comodíssim per encadenar exploracions sense declarar variables intermèdies.

> [2500, 2200, 1800, 1500].reduce((suma, p) => suma + p, 0)
8000
> _ / 4
2000
> _ / 100
20

Hi ha una variable germana, _error, que guarda l'últim error llançat:

> JSON.parse('{ aixo 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"

Compte: si assignes manualment _ = 5, perds aquesta funcionalitat en aquella sessió (el REPL t'avisa). Evita fer servir _ com a nom de variable pròpia.

  1. Autocompletat, historial i navegació

Aquestes tecles converteixen el REPL en una cosa realment ràpida:

Tecla Efecte
Tab Autocompleta. Si hi ha diverses opcions, prem-la dues vegades per llistar-les
↑ / ↓ Recorre l'historial d'ordres
Ctrl+R Cerca inversa a l'historial (escriu part de l'ordre)
Ctrl+A / Ctrl+E Anar al principi / final de la línia
Ctrl+U Esborrar la línia sencera
Ctrl+L Netejar la pantalla
Ctrl+C Cancel·lar la línia actual (dues vegades: sortir)
Ctrl+D Sortir

L'autocompletat és la joia. Escriu un objecte i un punt, i prem Tab:

> const sessio = { id: 'ses-001-1', aforament: 420, venudes: 180 }
undefined
> sessio.
sessio.__proto__             sessio.constructor           sessio.hasOwnProperty
...
sessio.aforament             sessio.id                    sessio.venudes

També funciona amb mòduls interns, cosa que el converteix en una documentació instantània:

> const path = require('node:path')
undefined
> path.
path.basename    path.dirname     path.extname     path.join
path.normalize   path.parse       path.relative    path.resolve

L'historial es conserva entre sessions al fitxer ~/.node_repl_history. Pots tancar el REPL, obrir-lo demà i recuperar amb ↑ el que has provat avui.

  1. Les ordres de punt

Tot el que comença per . al REPL és una ordre del mateix REPL, no JavaScript.

Ordre Què fa
.help Llista totes les ordres disponibles
.break Abandona una expressió multilínia a mitges (àlies: Ctrl+C)
.clear Reinicia el context: esborra totes les teves variables
.editor Entra en mode editor multilínia
.exit Surt del REPL
.load <fitxer> Carrega i avalua un fitxer a la sessió actual
.save <fitxer> Desa en un fitxer tot el que has escrit a la sessió

Exemple del cicle complet .load / .save:

> .save informes/sessio-repl.js
Session saved to: informes/sessio-repl.js

.save escriu totes les línies que has teclejat (no els resultats). És una manera còmoda de rescatar una exploració que ha sortit bé i convertir-la en el punt de partida d'un script.

.break et salva de l'embús clàssic:

> const esdeveniment = {
...   titol: 'Concierto de Otono',
... .break
>

Sense .break (o Ctrl+C), el REPL es queda esperant eternament el tancament de la clau.

.clear mereix un avís: reinicia el context i perds totes les variables definides. Fes-lo servir quan vulguis començar de zero, no per error.

  1. Carregar el catàleg d'Escena Viva al REPL

Aquí hi ha l'aplicació pràctica de .load. Prepararem un fitxer que contingui només les dades, sense la part de presentació ni el filtratge per arguments, per poder carregar-lo netament al REPL.

Crea src/cataleg-dades.js:

// src/cataleg-dades.js
// Nomes les dades del cataleg, sense logica de presentacio.
// Al modul 2 hi afegirem module.exports per poder reutilitzar-lo
// des d'altres fitxers; de moment serveix per carregar-lo al REPL amb .load

const cataleg = [
  {
    id: 'evt-001',
    titol: 'Concierto de Otono',
    sala: 'Teatro Almendra',
    categoria: 'concert',
    duracioMinuts: 95,
    sessions: [
      { id: 'ses-001-1', dataHora: '2026-10-03T20:00:00', aforament: 420, venudes: 180, preuCentims: 2500 },
      { id: 'ses-001-2', dataHora: '2026-10-04T19:00:00', aforament: 420, venudes: 96,  preuCentims: 2200 }
    ]
  },
  {
    id: 'evt-002',
    titol: 'Noche de Monologos',
    sala: 'Sala Boveda',
    categoria: 'humor',
    duracioMinuts: 80,
    sessions: [
      { id: 'ses-002-1', dataHora: '2026-10-10T21:30:00', aforament: 120, venudes: 118, preuCentims: 1800 },
      { id: 'ses-002-2', dataHora: '2026-10-11T21:30:00', aforament: 120, venudes: 45,  preuCentims: 1800 },
      { id: 'ses-002-3', dataHora: '2026-10-17T21:30:00', aforament: 120, venudes: 12,  preuCentims: 1500 }
    ]
  },
  {
    id: 'evt-003',
    titol: 'Festival de Jazz de Primavera',
    sala: 'Auditorio Ribera',
    categoria: 'festival',
    duracioMinuts: 240,
    sessions: [
      { id: 'ses-003-1', dataHora: '2027-04-17T19:00:00', aforament: 900, venudes: 640, preuCentims: 3800 },
      { id: 'ses-003-2', dataHora: '2027-04-18T19:00:00', aforament: 900, venudes: 720, preuCentims: 4200 }
    ]
  }
];

Ara, des de l'arrel del projecte:

cd escena-viva
node
> .load src/cataleg-dades.js

El REPL mostra el contingut del fitxer mentre l'avalua línia a línia. En acabar, la constant cataleg existeix a la teva sessió:

> cataleg.length
3
> cataleg[0].titol
'Concierto de Otono'

Punt important: .load no és el mateix que require. .load copia i avalua el text del fitxer dins del context del REPL, com si l'haguessis teclejat. require carrega un mòdul aïllat i només et dona el que aquell mòdul exporta. Per això .load funciona encara que el fitxer no exporti res, i per això és l'eina ideal per explorar. Els mòduls de debò arriben al Mòdul 2.

  1. Explorar i transformar les dades en directe

Amb el catàleg carregat, comença el que és divertit: provar transformacions abans d'escriure-les a l'script.

Veure la forma de les dades

> cataleg.map((e) => e.titol)
[ 'Concierto de Otono', 'Noche de Monologos', 'Festival de Jazz de Primavera' ]

> cataleg[1].sessions.length
3

Per inspeccionar un objecte imbricat sense que Node el retalli amb [Object]:

> console.dir(cataleg[0], { depth: null })

filter: quedar-se amb part del catàleg

> cataleg.filter((e) => e.sala === 'Sala Boveda').map((e) => e.titol)
[ 'Noche de Monologos' ]

> cataleg.filter((e) => e.duracioMinuts > 90).map((e) => e.titol)
[ 'Concierto de Otono', 'Festival de Jazz de Primavera' ]

flatMap: aplanar totes les sessions

Les sessions estan imbricades dins de cada esdeveniment. Per treballar amb totes alhora:

> const sessions = cataleg.flatMap((e) => e.sessions)
undefined
> sessions.length
7

I si necessitem saber a quin esdeveniment pertany cadascuna, afegim la dada en aplanar:

> const sessions = cataleg.flatMap((e) => e.sessions.map((s) => ({ ...s, esdeveniment: e.titol, sala: e.sala })))
undefined
> sessions[0]
{
  id: 'ses-001-1',
  dataHora: '2026-10-03T20:00:00',
  aforament: 420,
  venudes: 180,
  preuCentims: 2500,
  esdeveniment: 'Concierto de Otono',
  sala: 'Teatro Almendra'
}

L'operador ... (propagació) copia totes les propietats de l'objecte original i hi afegeix les noves. L'estudiarem formalment a la lliçó següent.

reduce: totals de negoci

> sessions.reduce((suma, s) => suma + s.aforament, 0)
3000

> sessions.reduce((suma, s) => suma + s.venudes, 0)
1811

> const ingressos = sessions.reduce((suma, s) => suma + s.venudes * s.preuCentims, 0)
undefined
> ingressos
6428600
> ingressos / 100
64286

Seixanta-quatre mil dos-cents vuitanta-sis euros de recaptació acumulada. Aquest és exactament el tipus de pregunta que respons en vint segons al REPL i que trigaries cinc minuts a programar, desar i executar.

sort i find

> sessions.filter((s) => s.sala === 'Auditorio Ribera').map((s) => s.id)
[ 'ses-003-1', 'ses-003-2' ]

> [...sessions].sort((a, b) => b.preuCentims - a.preuCentims)[0].id
'ses-003-2'

> sessions.find((s) => s.venudes / s.aforament < 0.2)
{ id: 'ses-002-3', ... }

Fixa't en el [...sessions] abans de sort: sort modifica l'array original. Copiar-lo primer evita alterar les dades que estàs explorant. És un error clàssic que el REPL t'ajuda a descobrir.

Ocupació per sala

> const perSala = {}
undefined
> for (const s of sessions) { perSala[s.sala] = (perSala[s.sala] ?? 0) + s.venudes }
undefined
> perSala
{ 'Teatro Almendra': 276, 'Sala Boveda': 175, 'Auditorio Ribera': 1360 }
> console.table(perSala)

L'operador ?? retorna el valor de la dreta només si el de l'esquerra és null o undefined. El veurem en detall a la lliçó vinent.

  1. El mode .editor per a funcions de diverses línies

Escriure una funció de deu línies al REPL línia a línia és incòmode: si t'equivoques a la tercera, no pots tornar enrere. Per a això hi ha .editor.

> .editor
// Entering editor mode (Ctrl+D to finish, Ctrl+C to cancel)
function resumSala(esdeveniments, sala) {
  const sessions = esdeveniments
    .filter((esdeveniment) => esdeveniment.sala === sala)
    .flatMap((esdeveniment) => esdeveniment.sessions);

  const aforament = sessions.reduce((total, s) => total + s.aforament, 0);
  const venudes = sessions.reduce((total, s) => total + s.venudes, 0);

  return {
    sala,
    sessions: sessions.length,
    aforament,
    venudes,
    ocupacio: `${Math.round((venudes / aforament) * 100)}%`
  };
}

Prem Ctrl+D per sortir del mode editor i avaluar tot el bloc de cop. Després prova-la:

> resumSala(cataleg, 'Teatro Almendra')
{ sala: 'Teatro Almendra', sessions: 2, aforament: 840, venudes: 276, ocupacio: '33%' }

> ['Teatro Almendra', 'Sala Boveda', 'Auditorio Ribera'].map((s) => resumSala(cataleg, s))
> console.table(['Teatro Almendra', 'Sala Boveda', 'Auditorio Ribera'].map((s) => resumSala(cataleg, s)))
┌─────────┬────────────────────┬──────────┬───────────┬─────────┬──────────┐
│ (index) │ sala               │ sessions │ aforament │ venudes │ ocupacio │
├─────────┼────────────────────┼──────────┼───────────┼─────────┼──────────┤
│ 0       │ 'Teatro Almendra'  │ 2        │ 840       │ 276     │ '33%'    │
│ 1       │ 'Sala Boveda'      │ 3        │ 360       │ 175     │ '49%'    │
│ 2       │ 'Auditorio Ribera' │ 2        │ 1800      │ 1360    │ '76%'    │
└─────────┴────────────────────┴──────────┴───────────┴─────────┴──────────┘

Quan la funció funciona, .save informes/exploracio.js desa la sessió i ja tens el codi a punt per enganxar-lo a src/.

Ctrl+D acaba, Ctrl+C cancel·la. Confondre'ls fa perdre el bloc sencer. A Windows, si Ctrl+D no respon, prova amb Ctrl+Z seguit d'Enter.

  1. Executar codi solt sense REPL: node -e i node -p

De vegades només vols una resposta i no una sessió interactiva. Node accepta codi directament des de la línia d'ordres.

Opció Significat Imprimeix el resultat
node -e "codi" evaluate: executa el codi No (fes servir console.log)
node -p "codi" print: executa i imprimeix el valor Sí, automàticament
# -e: cal imprimir explicitament
node -e "console.log(2 + 2)"
# 4

# -p: imprimeix el valor de l'expressio
node -p "2 + 2"
# 4

# Consultar la versio des d'un script de desplegament
node -p "process.version"
# v24.5.0

# Comprovar si un paquet esta installat i quina versio te
node -p "require('express/package.json').version"

Un cas molt pràctic: processar un fitxer JSON des del terminal sense instal·lar eines addicionals.

# Quants esdeveniments hi ha al fitxer llavor
node -p "require('./dades/esdeveniments.json').length"

# Titols dels esdeveniments, un per linia
node -e "require('./dades/esdeveniments.json').forEach(e => console.log(e.titol))"

Node sap llegir un .json amb require i retornar-lo ja convertit en objecte. Aquest truc et resoldrà moltes comprovacions ràpides a partir del Mòdul 3, quan el fitxer dades/esdeveniments.json sigui la font real del catàleg.

També pots encadenar el REPL amb una canonada, encara que en aquest cas no veuràs el símbol >:

echo "console.log(process.platform)" | node
# linux

  1. Peculiaritats: promeses, await de nivell superior i altres sorpreses

Promeses i await

El REPL de Node admet await al nivell superior, cosa que en un fitxer .js de tipus CommonJS no es pot fer. Això el converteix en un banc de proves excel·lent per a codi asíncron (tema del Mòdul 2).

> const fs = require('node:fs/promises')
undefined
> const text = await fs.readFile('src/cataleg-dades.js', 'utf8')
undefined
> text.length
1893

Si no fas servir await, el REPL et mostra la promesa, no el seu valor:

> fs.readFile('src/cataleg-dades.js', 'utf8')
Promise { <pending> }

Poc després el REPL imprimeix el resultat resolt pel seu compte, cosa que pot semblar que «apareix del no-res». No t'alarmis: és el REPL informant que la promesa s'ha resolt.

Altres peculiaritats que convé conèixer

Situació Què passa Per què
{ a: 1 } retorna 1 El REPL interpreta {} com un bloc, no com un objecte Embolcalla'l entre parèntesis: ({ a: 1 })
let x = 1 dues vegades dona error Redeclaració al mateix àmbit Fes servir var, o .clear, o canvia de nom
Un array llarg es retalla amb ... 73 more items Límit d'impressió de l'inspector console.dir(arr, { maxArrayLength: null })
Els objectes profunds mostren [Object] Profunditat d'inspecció per defecte: 2 console.dir(obj, { depth: null })
El REPL no veu les variables d'un fitxer carregat amb require require aïlla el mòdul Fes servir .load per explorar
Un error no tanca el REPL Els errors es capturen i es mostren És intencionat: pots continuar treballant

Prova tu mateix la primera:

> { titol: 'Concierto de Otono' }
'Concierto de Otono'
> ({ titol: 'Concierto de Otono' })
{ titol: 'Concierto de Otono' }

En el primer cas, JavaScript llegeix { com a inici de bloc i titol: com una etiqueta; el valor del bloc és l'última expressió. Amb parèntesis, es força la interpretació com a objecte literal.

  1. Quan fer servir el REPL i quan no

El REPL és una eina d'exploració, no de construcció. Aquesta taula resumeix l'elecció correcta:

Necessitat Eina adequada
Comprovar què retorna una expressió REPL
Explorar la forma d'unes dades desconegudes REPL (.load + console.dir)
Provar una transformació abans d'escriure-la REPL o .editor
Consultar l'API d'un mòdul REPL + Tab
Una comprovació puntual des d'un script de shell node -p
Codi que s'ha de repetir o versionar Un fitxer a src/
Lògica de més de 30 línies Un fitxer, encara que l'hagis prototipada al REPL
Entendre per què falla un programa complex en un punt concret El depurador (Mòdul 9)
Garantir que una cosa continua funcionant demà Proves automatitzades (Mòdul 9)

La regla és senzilla: si necessitaràs el resultat més d'una vegada, no pertany al REPL. Prototipa al REPL, desa amb .save, refina en un fitxer.

I sobre el depurador: el REPL et diu què fa una expressió aïllada; el depurador et deixa aturar un programa en marxa, a la línia que vulguis, i inspeccionar-ne totes les variables en aquell instant. Són complementaris, no alternatius.

Errors Comuns i Consells

Error 1: alarmar-se pel undefined després de cada declaració. És el valor de l'expressió, no una errada. const x = 5 no produeix cap valor.

Error 2: escriure { clau: valor } esperant un objecte. El REPL ho llegeix com un bloc. Embolcalla'l entre parèntesis.

Error 3: quedar-se atrapat al símbol .... Has deixat una clau, un parèntesi o una cometa sense tancar. Surt-ne amb .break o Ctrl+C.

Error 4: confondre .load amb require. .load avalua el text a la teva sessió (veus totes les variables). require retorna només el que s'ha exportat.

Error 5: fer servir .clear sense voler. Esborra totes les variables de la sessió. Si has invertit temps a carregar i transformar dades, primer .save.

Error 6: ordenar amb sort i espatllar l'array original. sort, reverse, splice, push i pop modifiquen l'array. Copia amb [...array] abans d'ordenar.

Consell 1: fes servir _ sense por. Encadenar _ és la manera més ràpida de refinar un càlcul pas a pas.

Consell 2: .save en acabar una exploració productiva. Desar a informes/ la sessió t'estalvia reconstruir el raonament demà.

Consell 3: el Tab és la teva documentació. Abans de buscar a internet quins mètodes té path, escriu path. i prem Tab dues vegades.

Consell 4: mantén un REPL obert en una pestanya del terminal. Amb el catàleg carregat, resoldre dubtes costa segons.

Exercicis

Exercici 1: exploració guiada del catàleg

Obre el REPL, carrega src/cataleg-dades.js amb .load i respon aquestes preguntes fent servir una sola expressió cada vegada. Anota l'ordre i el resultat.

  1. Quantes sessions hi ha en total al catàleg?
  2. Quin és el preu mitjà d'una entrada, en euros?
  3. Quins esdeveniments tenen més de dues sessions?
  4. Quantes entrades queden sense vendre a tot el catàleg?
  5. Quina és la sessió més cara i a quin esdeveniment pertany?

Exercici 2: funció en mode editor

Fent servir .editor, escriu una funció sessionsPerMes(esdeveniments) que retorni un objecte on cada clau sigui el mes en format AAAA-MM i el valor el nombre de sessions programades aquell mes. Prova-la amb el catàleg i mostra'n el resultat amb console.table. Després desa la sessió a informes/exploracio-mesos.js amb .save.

Pista: sessio.dataHora és una cadena ISO com '2026-10-03T20:00:00', així que el mes es pot extreure amb slice(0, 7).

Exercici 3: comprovacions des del terminal

Sense obrir el REPL, escriu les ordres node -e o node -p que resolguin el següent:

  1. Imprimir la versió major de Node instal·lada (només el número, per exemple 24).
  2. Imprimir quants mil·lisegons falten des d'ara fins al Concierto de Otono (2026-10-03T20:00:00).
  3. Convertir 4200 cèntims a la cadena '42.00'.
  4. Comprovar si la carpeta informes existeix al projecte (imprimir true o false).

Solucions

Solució 1

> .load src/cataleg-dades.js

# 1. Total de sessions
> cataleg.reduce((total, e) => total + e.sessions.length, 0)
7

# 2. Preu mitja en euros
> cataleg.flatMap(e => e.sessions).reduce((s, x, i, a) => s + x.preuCentims / a.length, 0) / 100
25.428571428571427

Alternativa més llegible, en dos passos amb _:

> cataleg.flatMap(e => e.sessions).map(s => s.preuCentims)
[ 2500, 2200, 1800, 1800, 1500, 3800, 4200 ]
> _.reduce((a, b) => a + b, 0) / _.length / 100
25.428571428571427

(17.800 cèntims entre 7 sessions = 2.542,86 cèntims, és a dir 25,43 EUR.)

# 3. Esdeveniments amb mes de dues sessions
> cataleg.filter(e => e.sessions.length > 2).map(e => e.titol)
[ 'Noche de Monologos' ]

# 4. Entrades sense vendre
> cataleg.flatMap(e => e.sessions).reduce((t, s) => t + (s.aforament - s.venudes), 0)
1189

# 5. Sessio mes cara i el seu esdeveniment
> cataleg.flatMap(e => e.sessions.map(s => ({ ...s, esdeveniment: e.titol })))
       .sort((a, b) => b.preuCentims - a.preuCentims)[0]
{ id: 'ses-003-2', ..., preuCentims: 4200, esdeveniment: 'Festival de Jazz de Primavera' }

Aquí sort sobre el resultat de flatMap és segur: aquest array és nou, no l'original.

Solució 2

> .editor
function sessionsPerMes(esdeveniments) {
  const recompte = {};

  for (const esdeveniment of esdeveniments) {
    for (const sessio of esdeveniment.sessions) {
      // '2026-10-03T20:00:00'.slice(0, 7) === '2026-10'
      const mes = sessio.dataHora.slice(0, 7);
      recompte[mes] = (recompte[mes] ?? 0) + 1;
    }
  }

  return recompte;
}

Ctrl+D i a provar:

> sessionsPerMes(cataleg)
{ '2026-10': 5, '2027-04': 2 }

> console.table(sessionsPerMes(cataleg))
┌─────────┬────────┐
│ (index) │ Values │
├─────────┼────────┤
│ 2026-10 │ 5      │
│ 2027-04 │ 2      │
└─────────┴────────┘

> .save informes/exploracio-mesos.js
Session saved to: informes/exploracio-mesos.js

Tingues en compte que .save desa tota la sessió, incloses les línies fallides. Revisa el fitxer abans de reutilitzar-lo.

Solució 3

# 1. Versio major de Node
node -p "process.versions.node.split('.')[0]"
# 24

# 2. Millisegons fins al Concierto de Otono
node -p "new Date('2026-10-03T20:00:00') - new Date()"
# 4483200000  (varia segons quan ho executis)

# 3. Centims a cadena amb dos decimals
node -p "(4200 / 100).toFixed(2)"
# 42.00

# 4. Comprovar si existeix la carpeta informes
node -p "require('node:fs').existsSync('informes')"
# true

Al punt 2, restar dos objectes Date els converteix automàticament a mil·lisegons des de l'època i retorna la diferència. Si prefereixes dies:

node -p "Math.ceil((new Date('2026-10-03T20:00:00') - Date.now()) / 86400000) + ' dies'"

Conclusió

El REPL és el laboratori de Node.js: un entorn on provar idees costa zero. Has après a arrencar-lo amb node, a interpretar l'undefined de les declaracions, a encadenar càlculs amb _, a moure't amb Tab i l'historial, i a manejar les ordres de punt —.help, .editor, .save, .load, .break, .clear, .exit—.

Ho has aplicat a Escena Viva creant src/cataleg-dades.js i carregant-lo amb .load per explorar en directe: aplanar sessions amb flatMap, calcular la recaptació acumulada amb reduce, detectar la sessió més cara amb sort o descobrir que hi ha 1.189 entrades per vendre. També has vist node -e i node -p per a comprovacions des del terminal, i les peculiaritats que confonen al principi: els objectes literals que necessiten parèntesis, les promeses pendents i l'await de nivell superior.

I sobretot tens clar el límit: el REPL serveix per explorar; el que s'ha de repetir va a un fitxer, i el que s'ha de garantir va a un test.

En aquesta exploració han aparegut, gairebé de contraban, eines del JavaScript modern: flatMap, l'operador de propagació ..., la coalescència nul·la ??, les funcions fletxa i la desestructuració. A la lliçó següent, JavaScript Modern per a Node.js, les estudiarem una per una i amb calma, sempre resolent un problema real del catàleg d'Escena Viva. És el repàs que sostindrà tot el codi que escriguis d'aquí al final del curs.

Curs de Node.js: De Principiant a Avançat

Mòdul 1: Introducció a Node.js

Mòdul 2: Conceptes Bàsics

Mòdul 3: Sistema de Fitxers i E/S

Mòdul 4: HTTP i Servidors Web

Mòdul 5: NPM i Gestió de Paquets

Mòdul 6: Framework Express.js

Mòdul 7: Bases de Dades i ORMs

Mòdul 8: Autenticació i Autorització

Mòdul 9: Proves i Depuració

Mòdul 10: Temes Avançats

Mòdul 11: Desplegament i DevOps

Mòdul 12: Projectes del Món Real

© Copyright 2026. Tots els drets reservats