W3docs

JavaScript eval()

Scopri come eval() in JavaScript esegue una stringa come codice: sintassi, valore restituito, chiamate dirette e indirette, rischi di sicurezza e alternative più sicure come il costruttore Function e JSON.parse().

JavaScript può trasformare una stringa in codice eseguibile a runtime. La funzione integrata eval() fa esattamente questo: riceve una stringa, la tratta come sorgente JavaScript e la esegue. Questa pagina spiega come funziona eval(), quando restituisce un valore, perché è quasi sempre lo strumento sbagliato e quali alternative usare al suo posto.

Questa pagina tratta:

  • La sintassi di eval() e cosa restituisce.
  • Casi d'uso reali (e perché la maggior parte di essi ha alternative migliori oggi).
  • I problemi di sicurezza e di prestazioni che rendono eval() pericoloso.
  • Alternative più sicure: il costruttore Function e JSON.parse().
  • Le buone pratiche per i rari casi in cui è davvero necessario.

Comprendere la funzione eval()

eval() valuta o esegue una stringa di codice JavaScript. Se la stringa è un'espressione, eval() la valuta e restituisce il risultato. Se la stringa contiene una o più istruzioni, eval() le esegue e restituisce il valore dell'ultima istruzione espressione (o undefined).

Sintassi

eval(string)

Parametri:

  • string — una stringa di codice sorgente JavaScript da valutare.

Valore restituito: il risultato dell'ultima espressione valutata, o undefined se la stringa non contiene espressioni.

Se string non è una stringa (ad esempio un numero), eval() restituisce l'argomento invariato.

Esempio di utilizzo

In questo esempio valutiamo una semplice espressione aritmetica e stampiamo il risultato:

javascript— editable

Casi d'uso pratici di eval()

Sebbene la funzione eval() possa essere estremamente potente, il suo utilizzo è spesso sconsigliato per motivi di sicurezza e prestazioni. Tuttavia, esistono scenari in cui eval() può essere utile.

Esecuzione dinamica del codice

Nelle situazioni in cui il codice deve essere generato ed eseguito dinamicamente, eval() può essere una soluzione pratica. Ad esempio, la creazione di una calcolatrice che valuta l'input dell'utente come espressione matematica:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Dynamic Calculator</title>
</head>
<body>
    <p>Add any arithmetic expression like 12 + 5 and hit 'Calculate' button!</p>
    <div>
        <input type="text" id="expression" placeholder="Enter expression" /> <!-- User input field -->
        <button onclick="evaluateExpression()">Calculate</button> <!-- Button to trigger calculation -->
    </div>
    <div id="calcResult"></div> <!-- Element to display result -->
    <script>
        function evaluateExpression() {
            const expression = document.getElementById('expression').value; // Get user input
            try {
                const result = eval(expression); // Evaluate the expression
                document.getElementById('calcResult').textContent = `Result: ${result}`; // Display the result
            } catch (e) {
                document.getElementById('calcResult').textContent = 'Invalid expression'; // Handle invalid input
            }
        }
    </script>
</body>
</html>

Parsing di JSON con eval()

Prima dell'introduzione di JSON.parse(), eval() veniva utilizzato per analizzare le stringhe JSON. Tuttavia, ora si raccomanda di usare JSON.parse() per motivi di sicurezza.

javascript— editable

Quando si usa eval() per analizzare stringhe JSON, è fondamentale assicurarsi che la stringa JSON venga interpretata come un'espressione object anziché come un blocco di istruzioni. Per ottenere questo risultato, la stringa JSON viene racchiusa tra parentesi prima di essere passata a eval(). Ciò garantisce che JavaScript tratti la stringa come un'espressione object, prevenendo gli errori di sintassi che potrebbero verificarsi se la stringa venisse interpretata come un blocco di istruzioni.

Informazione

Preferisci sempre JSON.parse() rispetto a eval() per analizzare il JSON. JSON.parse() accetta solo dati, quindi non potrà mai eseguire uno script iniettato.

eval() diretto vs. indiretto e scope

Il modo in cui eval() vede le variabili dipende da come lo chiami.

Una chiamata direttaeval(code) scritto letteralmente — esegue il codice nello scope corrente. Può leggere e persino creare variabili nel punto in cui viene chiamato:

javascript— editable

Una chiamata indiretta — richiamare eval attraverso qualsiasi riferimento diverso dal nome letterale, come (0, eval)(code) o memorizzandolo in una variabile — esegue il codice nello scope globale. Non può vedere le variabili locali:

javascript— editable

In strict mode, anche un eval() diretto ottiene il proprio scope: le variabili che dichiara non fuoriescono nella funzione circostante. Questo è un ulteriore motivo per cui il codice moderno raramente ha bisogno di eval().

Problemi di sicurezza e prestazioni

L'uso di eval() può comportare significativi rischi di sicurezza e problemi di prestazioni. Ecco perché:

Rischi di sicurezza

eval() può eseguire qualsiasi codice JavaScript, rendendolo vulnerabile agli attacchi di tipo injection. Un aggressore potrebbe iniettare codice malevolo, causando gravi violazioni della sicurezza.

Esempio di rischio di sicurezza:

Immagina di avere un'applicazione web che riceve input dall'utente e lo valuta con eval(). Senza una corretta validazione, questo può essere sfruttato da un aggressore per eseguire codice malevolo.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>eval() Security Risk Example</title>
</head>
<body>
    <div>
     <p>Hit 'Run Code' button!</p>
        <input type="text" id="userInput" placeholder="Enter code" value="alert('Hacked!')" /> <!-- User input field -->
        <button onclick="evaluateUserInput()">Run Code</button> <!-- Button to run code -->
    </div>
    <div id="userInputResult"></div> <!-- Element to display result -->
    <script>
        function evaluateUserInput() {
            const input = document.getElementById('userInput').value; // Get user input
            try {
                const result = eval(input); // Evaluate the user input
                document.getElementById('userInputResult').textContent = `Result: ${result}`; // Display the result
            } catch (e) {
                document.getElementById('userInputResult').textContent = 'Error in evaluation'; // Handle evaluation error
            }
        }
    </script>
</body>
</html>

In questo esempio, se un utente inserisce qualcosa come alert('Hacked!'), la funzione eval() lo eseguirà, causando una violazione della sicurezza mostrando una finestra di avviso. Un aggressore potrebbe iniettare codice ancora più dannoso, compromettendo potenzialmente l'intero sistema.

Problemi di prestazioni

eval() esegue il codice nello stesso scope dal quale viene chiamato, ostacolando le ottimizzazioni del motore JavaScript. Questo può portare a prestazioni più lente rispetto ad altri approcci.

Esempio di problema di prestazioni:

Consideriamo uno scenario in cui dobbiamo eseguire una serie di calcoli più volte. Usare eval() per questo compito può influire significativamente sulle prestazioni.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Performance Issues with eval()</title>
</head>
<body>
    <div id="evalResult"></div>
    <div id="functionResult"></div>
    <script>
        // Using eval()
        const evalStartTime = performance.now();
        for (let i = 0; i < 100000; i++) {
            eval("3 * 4 + 5");
        }
        const evalEndTime = performance.now();
        const evalDuration = evalEndTime - evalStartTime;
        document.getElementById('evalResult').textContent = `Time taken with eval(): ${evalDuration} ms`;

        // Using Function constructor
        const func = new Function('return 3 * 4 + 5');
        const funcStartTime = performance.now();
        for (let i = 0; i < 100000; i++) {
            func();
        }
        const funcEndTime = performance.now();
        const funcDuration = funcEndTime - funcStartTime;
        document.getElementById('functionResult').textContent = `Time taken with Function constructor: ${funcDuration} ms`;
    </script>
</body>
</html>

In questo esempio, confrontiamo le prestazioni di eval() con il costruttore Function. Eseguiamo una semplice operazione aritmetica (3 * 4 + 5) 100.000 volte con entrambi i metodi e misuriamo il tempo impiegato da ciascuno.

  • Usando eval(): Il codice all'interno di eval() viene valutato ripetutamente, il che è più lento perché impedisce alcune ottimizzazioni.
  • Usando il costruttore Function: Il costruttore Function crea una funzione che esegue la stessa operazione, ma è più veloce perché consente ai motori JavaScript di ottimizzare l'esecuzione ripetuta.

I risultati visualizzati sulla pagina web mostrano il tempo impiegato da ciascun metodo, dimostrando che eval() è più lento a causa dei suoi problemi di prestazioni.

Attenzione

Evita eval() a meno che non sia assolutamente necessario. Opta prima per alternative più sicure: il costruttore Function per funzioni dinamiche, o JSON.parse() per i dati.

Alternative a eval()

Per un'esecuzione del codice più sicura ed efficiente, considera le seguenti alternative:

Uso del costruttore Function

Il costruttore Function crea un nuovo object funzione, simile a eval(), ma con maggiore sicurezza e prestazioni migliori.

javascript— editable

Uso di JSON.parse()

Per analizzare le stringhe JSON, JSON.parse() è il metodo preferito.

javascript— editable

Buone pratiche per l'uso di eval()

Se devi usare eval(), segui queste buone pratiche per ridurre i rischi:

1. Valida l'input

Assicurati che l'input passato a eval() sia rigorosamente validato per prevenire l'iniezione di codice. Ciò significa consentire solo caratteri ed espressioni sicuri.

Esempio:

javascript— editable

In questo esempio, utilizziamo un'espressione regolare per validare l'input dell'utente. Sono consentiti solo caratteri numerici e operatori aritmetici di base. Se l'input corrisponde al pattern, viene valutato con eval(). Altrimenti, viene rifiutato come non valido.

2. Usa Try-Catch

Racchiudi eval() in un blocco try-catch per gestire eventuali errori in modo controllato. Questo impedisce all'intera applicazione di bloccarsi se eval() incontra un errore.

Esempio:

javascript— editable

Qui gestiamo gli errori di sintassi nell'input dell'utente usando un blocco try-catch. Se eval() lancia un errore, viene intercettato e viene registrato un messaggio di errore invece di bloccare l'applicazione.

3. Limita lo scope

Riduci al minimo lo scope delle variabili accessibili a eval() per limitare i potenziali danni da codice malevolo. Usa un'espressione di funzione immediatamente invocata (IIFE) per creare uno scope locale.

Esempio:

javascript— editable

In questo esempio, definiamo una funzione restrictedEval all'interno di una IIFE per creare uno scope locale. Questa funzione valuta l'input usando eval() ma con variabili a e b definite localmente. Le variabili globali a e b non sono accessibili, dimostrando la restrizione dello scope.

Seguendo queste buone pratiche, puoi ridurre i rischi associati all'uso di eval() pur sfruttando le sue capacità di esecuzione dinamica del codice quando necessario.

Conclusione

La funzione eval() in JavaScript offre uno strumento potente per l'esecuzione dinamica del codice, ma comporta rischi significativi e svantaggi in termini di prestazioni. In pratica, quasi qualsiasi attività che sembra richiedere eval() ha una soluzione più sicura: usa JSON.parse() per i dati, il costruttore Function per le funzioni dinamiche, e lookup su object/array invece di costruire nomi di variabili da stringhe. Se devi usare eval(), valida l'input, racchiudilo in try...catch, e mantieni il suo scope il più piccolo possibile.

Argomenti correlati

Esercitazione

Pratica
Cosa fa la funzione eval() in JavaScript?
Cosa fa la funzione eval() in JavaScript?
Was this page helpful?