7 marzo 2021

Eval: eseguire una stringa di codice

La funzione integrata eval consente di eseguire stringhe di codice.

La sintassi da utilizzare è:

let result = eval(code);

Ad esempio:

let code = 'alert("Hello")';
eval(code); // Hello

Una stringa di codice può essere molto lunga, contenere interruzioni di riga, dichiarazioni di funzione, variabili e cosi via.

Il risultato ritornato da eval corrisponde a quello dell’ultima istruzione.

Ad esempio:

let value = eval('1+1');
alert(value); // 2
let value = eval('let i = 0; ++i');
alert(value); // 1

Il codice valutato viene eseguito nel lexical environment corrente, quindi può accedere alle variabili esterne:

let a = 1;

function f() {
  let a = 2;

  eval('alert(a)'); // 2
}

f();

Allo stesso modo, può modificare le variabili esterne:

let x = 5;
eval("x = 10");
alert(x); // 10, valore modificato

In strict mode, eval viene eseguito in un lexical environment separato. Quindi le funzioni e le variabili dichiarate internamente, non sono visibili all’esterno:

// attenzione: 'use strict' è abilitato di default negli esempi che stiamo eseguendo

eval("let x = 5; function f() {}");

alert(typeof x); // undefined (variabile inesistente)
// anche la funzione f non è visibile

Senza use strict, eval non viene eseguito in un lexical environment separato, quindi saremo in grado di vedere x e f dall’esterno.

Utilizzare “eval”

Nella programmazione moderna eval viene utilizzato di rado. Spesso si dice “eval is evil” (“eval è il diavolo”).

La motivazione è piuttosto semplice: molto tempo fa, JavaScript era un linguaggio molto povero, molte cose potevano essere fatte solamente tramite eval. Ma quei tempi, ormai sono passati da un decennio.

Al momento, non esiste alcuna ragione per utilizzare eval. Se qualcuno lo sta utilizzando, c’è una buona possibilità che questo sia rimpiazzabile con un costrutto del linguaggio oppure con un modulo JavaScript.

Fate attenzione: la sua capacità di accedere alle variabile esterne può generare side-effects.

I code minifiers (strumenti utilizzati per comprimere gli script JS prima di metterli in produzione) rinominano le variabili locali con nomi più brevi (come a, b etc) in modo da rendere il codice più breve. Questa operazione, solitamente, è sicura. Non lo è, però, se stiamo utilizzando eval, poiché al suo interno potremmo provare ad accedere alle variabili locali. Quindi i minifiers non rinominano tutte le variabili che sono potenzialmente accessibili da eval. Questo comporta un peggioramento del fattore di compressione del codice.

L’utilizzo delle variabili locali all’interno di eval è considerata una bad practice nella programmazione, poiché rende il codice molto più complesso da mantenere.

Esistono due modi per mettersi al sicuro da questi problemi.

Se il codice all’interno di eval non richiede variabili esterne, allora invocate eval