30 mars 2020

Eval : exécution d'un texte code

La fonction intégrée eval permet d’exécuter une chaîne de caractère comprenant du code.

La syntaxe est :

let result = eval(code);

Par exemple:

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

Une chaîne de code peut être long, contenir des sauts à la ligne, des déclarations de fonctions, de variables et autres.

Le résultat de eval est le résultat de la dernière instruction.

For example:

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

Le code évalué est exécuté dans l’environnement lexical actuel, il peut donc voir les variables extérieures :

let a = 1;

function f() {
  let a = 2;

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

f();

Il peut également changer les variables extérieures :

let x = 5;
eval("x = 10");
alert(x); // 10, valeur modifiée

En mode strict, eval a son propre environnement lexical. Donc les fonctions et variables, déclarées au sein de l’eval, ne sont pas visibles en dehors :

// rappel : 'use strict' est actif par défaut dans les exemples exécutables

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

alert(typeof x); // undefined (pas de telle variable)
// la fonction f n'est pas visible non plus

Sans use strict, eval n’a pas d’environnement lexical propre, donc nous verrions x et f en dehors.

Utiliser “eval”

Dans la programmation moderne, eval est utilisé avec beaucoup de parcimonie. Il est souvent dit que “eval est le mal”.

La raison est simple : il y a très, très longtemps, JavaScript était un langage beaucoup plus faible, beaucoup de choses ne pouvaient être faites que par l’intermédiaire de eval. Mais ce temps est passé depuis une décennie.

À l’heure actuelle, il n’y a presque aucune raison eval. Si quelqu’un l’utilise, il y a de fortes chances pour qu’il/elle puisse le remplacer par une construction plus moderne ou un Module JavaScript.

Veuillez noter que son accessibilité aux variables extérieures a des effets secondaires.

Les minifacteurs de code (outils utilisés avant que JS parte en production, pour le compresser) renomment les variables locales avec des noms plus courts (comme a, b etc) pour rendre le code plus court. C’est souvent sûr, mais pas si eval est utilisé, étant donné que les variables locales peuvent être accessibles par le code évalué. Donc les minifacteurs ne font pas ce travail pour toutes les variables potentiellement visibles par le eval. Cela affecte négativement le ratio de compression.

Utiliser les variables locales extérieures dans un eval est de plus considéré comme une mauvaise pratique, étant donné que cela réduit la maintenabilité du code.

Il y a deux moyens pour être entièrement sûrs d’éviter de tels problèmes.

Si le code évalué n’a pas besoin des variables extérieures, appelez eval via window.eval(...):

De ce fait, le code est exécuté dans la portée globale:

let x = 1;
{
  let x = 5;
  window.eval('alert(x)'); // 1 (variable globale)
}

Si le code évalué a besoin des variables extérieures, changez eval par new Function et passez-le comme argument :

let f = new Function('a', 'alert(a)');

f(5); // 5

La construction new Function est expliquée dans le chapitre La syntaxe "new Function". Elle crée une fonction à partir d’une chaîne de caractères dans la portée globale. Elle ne peut donc pas voir les variables locales. Mais c’est beaucoup plus clair de les passer explicitement comme arguments, comme dans l’exemple ci-dessus.

Résumé

Un appel de eval(code) exécute la chaîne de code et retourne le résultat de la dernière instruction.

  • Rarement utilisé dans le JavaScript moderne, puisque souvent inutile.
  • Peut accéder aux variables locales extérieures. C’est considéré comme une mauvaise pratique.
  • À la place, pour eval le code dans la portée globale, utilisez window.eval(code).
  • Sinon, si votre code a besoin de données de la portée extérieure, utilisez new Function et passez-le comme argument.

Exercices

importance: 4

Créez une calculatrice qui demande une expression arithmétique et retourne son résultat.

Il n’y a pas besoin de vérifier l’exactitude de l’expression. Évaluez simplement la et retournez le résultat.

Exécuter la démo

Utilisons eval pour calculer l’expression mathématique :

let expr = prompt("Type an arithmetic expression?", '2*3+2');

alert( eval(expr) );

L’utilisateur peut envoyer n’importe quel texte ou code cependant.

Pour rendre les choses sûres, et les limiter à de l’arithmétique, nous pouvons vérifier expr en utilisant une expression régulière, pour qu’elle ne contienne que des nombres et des opérateurs.

Carte du tutoriel

Commentaires

lire ceci avant de commenter…
  • Si vous avez des améliorations à suggérer, merci de soumettre une issue GitHub ou une pull request au lieu de commenter.
  • Si vous ne comprenez pas quelque chose dans l'article, merci de préciser.
  • Pour insérer quelques bouts de code, utilisez la balise <code>, pour plusieurs lignes -- enveloppez-les avec la balise <pre>, pour plus de 10 lignes - utilisez une sandbox (plnkr, jsbin, codepen…)