come sostituire eval() in Javascript

Javascript è un linguaggio che suscita amori ed odi, nato per dare un poco di vita all’esangue staticità delle pagine HTML è diventato sempre più autonomo ed importante. L’avvento di AJAX ne ha ulteriormente aumentato l’importanza nella programmazione lato client e sono ormai miglia i tool e librerie disponibili.
Infine con nodejs è diventato possibile, ed interessante, anche il suo utilizzo lato server. In verità questo è possibile da tempo con rhino ma si tratta di una soluzione che dipende da java e quindi non offre gli stimoli sufficienti per sostituire java stesso.
Alcuni link per una panoramica sugli ultimi sviluppi di Javascript e sulle sue potenzialità:
crockford
In particolare  (anche in italiano) JavaScript:The Good Parts.
Javascript: Il linguaggio di programmazione più incompreso del mondo
Una reintroduzione a Javascript

In Javascript è disponibile per l’esecuzione dinamica del codice in formato string la funzione eval(codeString).
Ad esempio invece di scrivere x=2+3; si può scrivere x=eval(“2+3”);
L’esempio è banale e dubito che venga in mente a qualcuno di utilizzare eval() in un caso come questo. Ma vi sono molte situazione nelle quali la tentazione è forte.
Ma in quasi tutti i migliori manuali su Javascript si sconsiglia di utilizzare eval() in quanto la si considera una funzione pericolosa per la sicurezza. Ho trovato varie motivazioni per questa accusa, la più ricorrente è la possibilità di accedere a variabili globali nel codice che si passa alla funzione. Ma per questo aspetto la colpa iniziale è in un cattivo uso delle variabili globali più che nella funzione stessa. Inoltre  si accusa eval() di non essere particolarmente efficiente, ma si tratta di un’accusa che la potenza dell’attuale hardware tende a vanificare e, in ogni caso, bisognerebbe fare un paragone con la specifica soluzione adottata per sostituire eval().
Il dato di fondo è che non ho trovato una soluzione generalizzata per sostituirlo ma solo la raccomandazione di organizzare diversamente il codice.
Nell’implementare un template lato client mi sono trovato in conflitto tra il rispetto dei consigli di tanti autorevoli autori ed il fatto che la funzione eval() mi faceva maledettamente comodo.
Ho cercato quindi una soluzione generale per sostituire eval(). Naturalmente le problematiche riguardanti l’uso del codice in formato stringa sono ineliminabili e possono essere risolte solo attraverso controlli sul codice stesso.
In Javascript una funzione può essere dichiara in vari modi:
Funzione globale:
function fn1(arg1,arg2){return arg1*arg2+100;}
fn1(2,3); // 106

Funzione assegnata ad una variabile:
var fn2=function(arg1,arg2){return arg1*arg2+100;}
fn2(2,3); // 106

Funzione letterale:
var fn3=new Function(“arg1,arg2”,”return arg1*arg2+100;”);
fn3(2,3); // 106

la soluzione proposta sfrutta la definizione di Funzione letterale.

var fnEval = function() {
 try {
   var pars, code;
   var l = arguments.length;
   var args = [];
   if (l > 2) {
     pars = arguments[0];
     code = arguments[1];
     for (var i = 2; i < l; i++)
       args[i - 2] = arguments[i];
   } else if (l == 1) {
     pars = "pars";
     code = arguments[0];
   } else {
     alert("arguments error ([params],code,[arg0,arg1,..])");
   }
   var fn = new Function(pars, code);
   try {
     return fn.apply(this,args);
   } catch (re) {
     alert("runtime error " + re);
     return null;
   }
 } catch (se) {
     alert("syntax error " + se);
     return null;
   }
}

Esempi:

fnEval("return 2*3;");
//6

fnEval("pars","return 2 * 3 * pars;",100);
//600

fnEval("x,y,z","return 2 * 3 +x+y+z;",10,20,100);
//136

La soluzione proposta permette non solo di eseguire il codice dinamicamente, ma anche di passare dei parametri ed i loro valori, cosa che non è possibile con eval(). Rispetto all’uso esplicito di new Function(){pars,code} offre il vantaggio di una maggiore compattezza e soprattutto permette di distinguere fra eventuali errori di sintassi nel codice passato alla funzione ed errori di runtime. Per poter passare i parametri ed i rispettivi valori senza limitazione di numero è stato usato l’espediente di invocare la funzione nella modalità fn.apply(this,args); dover args è un array dei valori dei parametri estratto da arguments della funzione fnEval().

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *