Performances

Douglas Crockford nous dit : "eval is evil", cela fait appel au compilateur du naviguateur et consomme beaucoup de ressources.
Testons avec mon script de benchmark la vitesse d'exécution de differentes fonctions utilisant (ou pas) eval().

Le test

  1. setTimeout("maFonction()",20);
  2. setTimeout(function () {maFonction() ;},20);
  3. maFonction.delay(20);

Dans la première ligne on écrit directement entre crochet le nom de la fonction. Cela fait appel implicitement à la fonction eval() du navigateur sur la chaine de caractère.
La seconde ligne est une solution plus propre : on créé une fonction anonyme qui va appeler notre fonction avec le même délai.
La troisième ligne se sert directement de la fonction delay() du framework Mootools ! (Mootools doit utiliser une méthode équivalente à la seconde ligne en plus riche)

Bref les trois instructions réalisent exactement la même chose.

Resultat (moyenne de 5 tests en ms) :

isEvilEvalSetTimeout

Conclusion

Pas la peine de vous faire un dessin, dans ce cas là l'appel à la fonction eval semble laisser indifférent les naviguateur. Il y a tout de même un gain de 1% avec Firefox (vérifié avec un plus grand nombre d'itérations).
Bon pas de quoi non plus vermifuger un abris de bus : la valeur de notre chaine qui passe dans eval() est minuscule !
Il se peut cependant que la mémoire consomée soit légerement plus importante avec le eval() mais que la difference soit trop faible pour que cela apparaisse dans les temps d'execution
Douglas Crockford rajoute dans ses conférences que le code executé par eval() ne pourra pas être optimisé par le compilateur js du naviguateur. Impossible de vérifier cela mais faisons lui confiance !

Le second test

Voila une erreur que j'ai déjà aperçu dans quelque script js :

  1. var myKey = 'unAttribut' ;
  2. //Methode affreuse !
  3. eval("test = globalObject." + myKey + ";");
  4. //Bonne methode
  5. test = globalObject[myKey] ;
  6.  
  7. //Boucles du benchmark :
  8. for(i=0;i<=1000;i++){
  9. test = globalObject[myKey] ;
  10. }
  11. for(i=0;i<=1000;i++){
  12. eval("test = globalObject." + myKey + ";");
  13. }

Resultat n°2 (moyenne de 10 tests en ms) :

isEvalEvilAffectation.png
La conclusion est simple : eval() ca prend quand même pas mal de ressources, alors que l'affectation de variable en utilisant directement les est casi instantanée !

Inconvéniants

Impossible de passer un objet en paramètre de la fonction dans un setTimeout("maFonction()",20).
Rien que pour ca, c'est à bannir définitivement !

Sécurité

Le principal problème lié à la fonction eval() est en fait surtout au niveau de la sécurité de votre application web.
La majorité des fonction eval() s'effectuent sur des chaines de caractères qui proviennent d'un page rechargée en ajax par exemple.
Ne pouvant pas être sur à 100% du contenu de la page ajax que recevra l'utilisateur (imaginons que quelqu'un traffic son proxy pour lui renvoyer de fausses données) vous avez une faille potentielle de sécurité.
Plus d'infos ici (en Anglais) Comment faire ?
- lancer des fonctions lors de la réception de la requête ajax qui récupèrerons les données et s'en serviront sans faire d'eval ().
(en gros ne pas mettre de fonction javascript dans votre page ajax, uniquement les paramètres que vous recuperez ensuite)
- Utiliser JSON et un parseur qui vous garantie la sécurité de l'eval() qu'utilise le parseur.

PS : le parseur JSON de Douglas Crockford (inventeur du JSON) utilise la fonction eval() mais sécurisée.
Celui-ci concéde que la fonction eval est à proscrire, mais qu'elle reste rapide comparée à d'autre méthodes plus complexes à mettre en oeuvre (ecrire un nouveau fichier .js avec le resultat du code par exemple) parceque les navigateur l'ont vraiment optimisé.