Best practice per l'iterazione in JavaScript

Best practice per l'iterazione in JavaScript

Questo articolo spiega le best practice per l'iterazione in JavaScript.

YouTube Video

Best practice per l'iterazione in JavaScript

In JavaScript, è comune utilizzare i cicli for per l'iterazione. Qui forniremo una spiegazione dettagliata delle best practice per utilizzare i cicli for per scrivere codice efficiente e leggibile.

Scegli la struttura di ciclo più adatta

JavaScript fornisce diversi costrutti di ciclo, ciascuno adatto per scopi diversi.

 1// Example of a for loop
 2for (let i = 0; i < 5; i++) {
 3    console.log(i);
 4}
 5
 6// Example of a for...of loop
 7const array = [10, 20, 30];
 8for (const value of array) {
 9    console.log(value);
10}
11
12// Example of a for...in loop
13const obj = { a: 1, b: 2, c: 3 };
14for (const key in obj) {
15    console.log(`${key}: ${obj[key]}`);
16}
17
18// Example of a while loop
19let count = 0;
20while (count < 5) {
21    console.log(count);
22    count++;
23}
  • L'istruzione for è adatta quando il numero di iterazioni è predeterminato.
  • L'istruzione for...of è adatta per elaborare in modo conciso array e oggetti iterabili.
  • L'istruzione for...in viene utilizzata per iterare sulle proprietà di un oggetto. Tuttavia, non è adatto per gli array.
  • Le istruzioni while e do...while vengono utilizzate per controllare i cicli in base a condizioni.

Utilizzo del metodo forEach e dell'istruzione for...of.

Durante l'iterazione di un array, è comune utilizzare un'istruzione for per accedere all'indice, ma il metodo forEach o l'istruzione for...of possono essere più leggibili.

 1// Using a standard for loop
 2const array = ["apple", "banana", "cherry"];
 3for (let i = 0; i < array.length; i++) {
 4    console.log(array[i]);
 5}
 6
 7// Using forEach
 8array.forEach(item => console.log(item));
 9
10// Using for...of
11for (const item of array) {
12    console.log(item);
13}
  • L'istruzione for consente una gestione esplicita degli indici durante l'iterazione.
  • Il metodo forEach utilizza una funzione di callback per elaborare ciascun elemento in modo conciso.
  • L'istruzione for...of è altamente leggibile e consente l'accesso diretto a ciascun elemento di un array.

Ottimizza le condizioni del ciclo

Poiché la condizione del ciclo viene valutata ripetutamente, evitare calcoli non necessari può migliorare le prestazioni.

 1const names = ["Alice", "Bob", "Charlie"];
 2const scores = [85, 92, 78];
 3
 4// Inefficient example
 5for (let i = 0; i < Math.min(names.length, scores.length); i++) {
 6    console.log(`${names[i]} scored ${scores[i]}`);
 7}
 8
 9// Efficient example
10for (let i = 0, len = Math.min(names.length, scores.length); i < len; i++) {
11    console.log(`${names[i]} scored ${scores[i]}`);
12}
  • Come mostrato in questo esempio, memorizzare il risultato del calcolo in una variabile in anticipo consente un'esecuzione del ciclo più efficiente.
 1const scores = [85, 92, 78];
 2let sum = 0;
 3let sum2 = 0;
 4
 5// Inefficient example
 6for (let i = 0; i < scores.length; i++) {
 7    sum += scores[i];
 8}
 9console.log(`Total score : ${sum}`);
10
11// Efficient example
12for (let i = scores.length - 1; i >= 0; i--) {
13    sum2 += scores[i];
14}
15console.log(`Total score : ${sum2}`);
  • Come mostrato in questo esempio, invertire la condizione può talvolta essere più efficiente.

Ottimizzazione dell'elaborazione dei cicli

Poiché l'elaborazione dei cicli viene eseguita ripetutamente, evitare calcoli inutili può migliorare le prestazioni.

 1const array = ["apple", "banana", "cherry"];
 2
 3// Inefficient example
 4for (let i = 0; i < 100; i++) {
 5    const element = document.querySelector("#myElement");
 6    element.textContent = `Count: ${i}`;
 7}
 8
 9// Efficient example
10const element = document.querySelector("#myElement");
11for (let i = 0; i < 100; i++) {
12    element.textContent = `Count: ${i}`;
13}
  • In questo esempio, spostando il metodo querySelector fuori dal ciclo, si eliminano calcoli inutilmente ripetuti.

Fai attenzione all’ambito delle variabili

Usa let o const per garantire che le variabili all'interno del ciclo abbiano l'ambito appropriato. Dato che var è limitato all’ambito delle funzioni, potrebbe causare comportamenti imprevisti.

 1// Using let
 2for (let i = 0; i < 3; i++) {
 3    console.log(i);
 4}
 5
 6// Potential issue with var
 7for (var i = 0; i < 3; i++) {
 8    setTimeout(() => console.log(i), 1000); // 3, 3, 3
 9}
10
11// Using let to avoid the issue
12for (let i = 0; i < 3; i++) {
13    setTimeout(() => console.log(i), 1000); // 0, 1, 2
14}
  • var ha uno scope di funzione, quindi dopo il ciclo i è pari a 3 e tutte le funzioni eseguite da setTimeout restituiranno 3.
  • Utilizzando let, l'i all'interno della funzione di callback di setTimeout si riferisce a un nuovo valore per ogni ciclo, quindi 0, 1, 2 vengono stampati come previsto.

Migliora la leggibilità con interruzioni anticipate

Per semplificare l'elaborazione dei cicli, usa break e continue in modo appropriato per migliorare la leggibilità.

 1// Example using break
 2for (let i = 0; i < 10; i++) {
 3    if (i === 5) {
 4        break; // Exit the loop
 5    }
 6    console.log(i);
 7}
 8
 9// Example using continue
10for (let i = 0; i < 10; i++) {
11    if (i % 2 === 0) {
12        continue; // Skip to the next iteration
13    }
14    console.log(i);
15}
  • Utilizzando break è possibile interrompere l'elaborazione del ciclo a metà, saltando tutte le iterazioni successive.
  • Utilizzando continue è possibile saltare l'elaborazione corrente del ciclo e passare all'iterazione successiva.

Evita annidamenti profondi

Gli annidamenti profondi rendono il codice più difficile da leggere, quindi cerca di mantenere gli annidamenti superficiali utilizzando ritorni anticipati o suddividendo le funzionalità in funzioni separate.

 1// Deeply nested example
 2for (let i = 0; i < 5; i++) {
 3    for (let j = 0; j < 5; j++) {
 4        if (i + j > 5) {
 5            console.log(i, j);
 6        }
 7    }
 8}
 9
10// Improved using function decomposition
11function processPairs(i) {
12    for (let j = 0; j < 5; j++) {
13        if (i + j > 5) {
14            console.log(i, j);
15        }
16    }
17}
18
19for (let i = 0; i < 5; i++) {
20    processPairs(i);
21}
  • In questo esempio, le funzioni vengono utilizzate per ridurre l'annidamento.

Prendi in considerazione la gestione degli errori

Se esiste la possibilità che si verifichino errori all'interno del ciclo, implementa una corretta gestione degli errori.

 1const data = ["123", "abc", "456", "xyz"];
 2
 3// Without Error Handling
 4for (const item of data) {
 5    const result = parseInt(item);
 6    console.log(`Parsed value: ${result}`);
 7}
 8
 9// With Error Handling
10for (const item of data) {
11    try {
12        const result = parseInt(item);
13        if (isNaN(result)) {
14            throw new Error(`Invalid number: ${item}`);
15        }
16        console.log(`Parsed value: ${result}`);
17    } catch (error) {
18        console.error(`Error processing item: ${item}. ${error.message}`);
19    }
20}
  • In questo esempio, la gestione degli errori viene eseguita per elaborare dati non validi, rilevando e segnalando eventuali problemi.

Punti da notare nella gestione asincrona

Quando si gestisce l'elaborazione asincrona nei cicli, l'uso di async/await può portare a un codice conciso e intuitivo.

 1const urls = ["https://example.com/1", "https://example.com/2"];
 2
 3// Proper handling of asynchronous operations
 4async function fetchUrls() {
 5    for (const url of urls) {
 6        const response = await fetch(url);
 7        const data = await response.json();
 8        console.log(data);
 9    }
10}
11
12fetchUrls();
  • Questo codice recupera in modo asincrono gli URL dall'array urls uno per uno ed elabora i risultati in formato JSON. L'utilizzo di async/await semplifica le operazioni asincrone, recuperando sequenzialmente i dati per ogni URL e stampandoli nella console.

Comprendi la differenza tra l'istruzione for...of e forEach() nell'elaborazione asincrona.

 1async function asyncTask(num) {
 2    return new Promise(resolve => {
 3        setTimeout(() => {
 4            console.log(`Task ${num} done`);
 5            resolve();
 6        }, 100);
 7    });
 8}
 9
10async function runWithForOf() {
11    console.log("Start for...of");
12    for (const num of [1, 2, 3]) {
13        await asyncTask(num);
14    }
15    console.log("End for...of");
16}
17
18async function runWithForEach() {
19    console.log("Start forEach");
20    [1, 2, 3].forEach(async num => {
21        await asyncTask(num);
22    });
23    console.log("End forEach");
24}
25
26async function executeExamples() {
27    await runWithForOf();
28    await runWithForEach();
29}
30
31executeExamples();
  • Quando gestisci l'elaborazione asincrona nei cicli, nota le differenze di comportamento, come mostrato in questo esempio, tra l'uso di for...of con async/await e l'uso di forEach().

  • Con for...of, il codice viene eseguito in modo sequenziale e aspetta al await all'interno del ciclo prima di passare all'iterazione successiva. D'altra parte, forEach() esegue l'elaborazione in parallelo.

Conclusione

L'istruzione for in JavaScript è uno strumento semplice ma potente. Seguendo le migliori pratiche introdotte qui, puoi scrivere codice efficiente e altamente leggibile. Fai attenzione a scegliere costrutti di ciclo appropriati, alla gestione dello scope, alla gestione degli errori e punta a scrivere codice altamente mantenibile.

Puoi seguire l'articolo sopra utilizzando Visual Studio Code sul nostro canale YouTube. Controlla anche il nostro canale YouTube.

YouTube Video