La console non è solo log
console.log è il primo strumento di debug che quasi tutti imparano e l'ultimo che molti smettono di usare. Funziona, ma l'oggetto console ha una dozzina di altri metodi che rendono il debug più veloce e chiaro. E una volta che ti troverai a tuo agio con i DevTools veri e propri (breakpoint, call stack, espressioni osservate), userai log molto meno di prima.
Cominciamo con una rapida panoramica:
Tutti e quattro stampano nella stessa console, ma i browser li mostrano con stili diversi: gli avvisi hanno lo sfondo giallo, gli errori sono rossi con un'icona, ed entrambi includono uno stack trace. I filtri dei DevTools ti permettono di nascondere o isolare ogni livello, cosa che conta quando un'app produce centinaia di messaggi.
Stampare più valori senza fatica
Quando vuoi vedere più variabili insieme, non concatenarle in una stringa. Passale come argomenti separati o, meglio ancora, racchiudile in un oggetto così ognuna ha la sua etichetta:
Il trucco di { user, count } sfrutta la sintassi abbreviata degli oggetti: il nome della variabile diventa la chiave. Nella console vedrai { user: {...}, count: 3 } e potrai espandere user per esaminarlo. Non perdi la struttura dell'oggetto trasformandolo in stringa.
console.table per gli array di oggetti
Quando hai davanti un array di oggetti, console.log ti dà un groviglio compresso. console.table lo mostra come una vera tabella:
Nella console di un browser, la prima chiamata stampa tutte e tre le righe con colonne ordinabili. La seconda si limita a name e role. È un enorme miglioramento della qualità della vita per tutto ciò che ha forma di dati: risposte delle API, risultati di query, CSV analizzati.
console.dir e console.log a confronto
Sembrano simili, ma si comportano in modo diverso con gli elementi del DOM:
const el = document.querySelector("button");
console.log(el); // prints the HTML: <button>Click me</button>
console.dir(el); // prints the JS object view with all properties
log formatta gli elementi come HTML. dir ti mostra l'oggetto: ogni proprietà, ogni event handler, ogni riferimento agli stili calcolati. Quando vuoi sapere quali metodi o attributi ha un elemento, quello giusto è dir.
Raggruppare l'output correlato
Le lunghe sessioni di debug riempiono la console di rumore. console.group e console.groupEnd racchiudono i messaggi correlati in un blocco che si può comprimere:
Ogni chiamata produce un gruppo con un nome che puoi comprimere. Usa console.groupCollapsed se vuoi che i gruppi partano già chiusi: è utile quando vuoi aprire solo quelli che sembrano sospetti.
Misurare il tempo con console.time
Per controlli rapidi sulle prestazioni, console.time e console.timeEnd sono difficili da battere:
L'etichetta di time e timeEnd deve coincidere. Puoi avere più timer attivi contemporaneamente con etichette diverse. Per qualcosa di più serio di "questo ciclo è lento?", passa al pannello Performance dei DevTools, che registra una timeline completa e un flame chart.
Asserzioni: stampare solo quando qualcosa non va
console.assert stampa solo quando la condizione è falsy. È un modo discreto per lasciare controlli di coerenza nel codice senza intasare la console quando va tutto bene:
Ottimo per gli invarianti che dovrebbero valere sempre. Pessimo per le cose che potrebbero legittimamente fallire: per quelle, lancia un errore.
Stack trace su richiesta
console.trace stampa lo stack delle chiamate corrente senza lanciare nulla. È comodo quando cerchi di capire chi ha chiamato una funzione:
L'output mostra inner → outer → (top level). In un'app reale è così che scopri che l'handler del clic su cui stai facendo debug viene attivato da tre punti diversi.
L'istruzione debugger
Il modo più veloce per mettere in pausa l'esecuzione di JavaScript è una sola parola:
function computeTotal(items) {
const subtotal = items.reduce((s, i) => s + i.price, 0);
debugger;
return subtotal * 1.08;
}
Quando i DevTools sono aperti, debugger; funziona come un breakpoint: l'esecuzione si ferma su quella riga e hai a disposizione il debugger completo, con le variabili nello scope, lo stack delle chiamate, i comandi step over e step into e la possibilità di valutare espressioni sullo stato corrente. Quando i DevTools sono chiusi, debugger; non fa nulla.
La prima volta che usi un vero debugger al posto di console.log, sembra un superpotere. Vedi ogni variabile nello scope senza dover decidere prima cosa stampare. Puoi attraversare i condizionali passo passo e vedere quale ramo viene eseguito. Risolvere un bug difficile passa da minuti a secondi.
Togli la riga debugger prima del commit o, meglio ancora, imposta i breakpoint direttamente nei DevTools cliccando sul numero di una riga nel pannello Sources.
Trucchi dei DevTools da conoscere
Alcune funzioni che molti ignorano per anni:
- Breakpoint condizionali: clic destro sul numero di una riga in Sources e imposta una condizione come
user.id === 42. Il breakpoint scatta solo quando la condizione è vera. - Logpoint: stesso menu, "Add logpoint". Stampa un messaggio senza mettere in pausa e senza modificare il codice.
$_nella console: l'ultima espressione valutata. Esegui qualcosa, poi usa$_per recuperarla.$0: l'elemento attualmente selezionato nel pannello Elements.$0.textContentesamina quello su cui hai cliccato.- Copiare come oggetto: clic destro su un valore nella console e scegli "Store as global variable". Ottieni
temp1,temp2e così via, da esplorare. - Pannello Network → Copy as fetch: trasforma qualsiasi richiesta in una chiamata
fetch()che puoi incollare nella console e modificare.
Nessuno di questi è indispensabile. Tutti ti fanno risparmiare tempo una volta diventati un'abitudine.
Fare pulizia prima di pubblicare
Le chiamate a console.log dimenticate sono innocue in sviluppo e rumorose in produzione. Alcune abitudini che aiutano:
- Usa una regola del linter (
no-consolein ESLint) per segnalare i log rimasti, con eccezioni perwarnederror. - Racchiudi i log dettagliati in un controllo:
if (process.env.NODE_ENV !== "production") console.log(...). - Preferisci
console.debugper l'output di tracciamento: la maggior parte dei bundler e degli aggregatori di log può filtrarlo. - Meglio ancora: usa un piccolo modulo di logging (o una libreria come
debug) per attivare e disattivare categorie di log senza modificare il codice.
Il logging non è gratis. Ogni chiamata serializza i suoi argomenti e scrive in un buffer. In un ciclo molto frequentato, un log dimenticato può rallentare le cose in modo misurabile.
Prossimo passo: le espressioni regolari
Farai molto debug di codice che elabora stringhe, e gran parte di quel codice usa le regex, la funzionalità più compatta e più criptica del linguaggio. Il prossimo capitolo inizia con un giro tranquillo tra le espressioni regolari di JavaScript e i metodi che le usano.
Domande frequenti
Che differenza c'è tra console.log e console.dir?
console.log stampa i valori con la formattazione predefinita del browser: per gli elementi del DOM significa mostrarli come HTML. console.dir stampa sempre la vista dell'oggetto JavaScript con le sue proprietà, ed è quello che ti serve quando vuoi esaminare le proprietà di un elemento invece del suo markup.
Come faccio il debug di JavaScript nei Chrome DevTools senza console.log?
Apri il pannello Sources, trova il tuo file e clicca sul numero di una riga per impostare un breakpoint. Quando l'esecuzione arriva a quella riga si mette in pausa, e puoi esaminare le variabili, procedere passo passo nel codice e valutare espressioni nella console. Puoi anche inserire un'istruzione debugger; nel codice per attivare un breakpoint direttamente dal sorgente.
Come misuro quanto tempo impiega il codice JavaScript?
Racchiudi il codice tra console.time('label') e console.timeEnd('label') con la stessa etichetta. La console stampa il tempo trascorso in millisecondi. Per un profiling più dettagliato, usa il pannello Performance dei DevTools per registrare un flame chart di tutto ciò che è stato eseguito.
A cosa serve console.table?
console.table mostra array e oggetti come una tabella ordinabile nella console, molto più facile da scorrere di un oggetto annidato stampato per intero. È perfetto per gli array di oggetti: ogni oggetto diventa una riga e le sue chiavi diventano colonne. Puoi passare un secondo argomento per scegliere quali colonne mostrare.