W3docs

JavaScript eval()

Apprenez comment eval() exécute une chaîne en tant que code : syntaxe, valeur de retour, appels directs/indirects, risques de sécurité et alternatives.

JavaScript peut transformer une chaîne en code exécutable à l'exécution. La fonction intégrée eval() fait exactement cela : elle prend une chaîne, la traite comme du code source JavaScript et l'exécute. Cette page explique comment eval() fonctionne, dans quels cas elle retourne une valeur, pourquoi c'est presque toujours le mauvais outil, et quelles alternatives privilégier.

Cette page couvre :

  • La syntaxe de eval() et ce qu'elle retourne.
  • Les cas d'usage réels (et pourquoi la plupart ont de meilleures alternatives aujourd'hui).
  • Les problèmes de sécurité et de performance qui rendent eval() dangereuse.
  • Les remplaçants plus sûrs : le constructeur Function et JSON.parse().
  • Les bonnes pratiques pour les rares cas où vous en avez vraiment besoin.

Comprendre la fonction eval()

eval() évalue ou exécute une chaîne de code JavaScript. Si la chaîne est une expression, eval() l'évalue et retourne le résultat. Si la chaîne contient une ou plusieurs instructions, eval() les exécute et retourne la valeur de la dernière instruction d'expression (ou undefined).

Syntaxe

eval(string)

Paramètres :

  • string — une chaîne de code source JavaScript à évaluer.

Valeur de retour : le résultat de la dernière expression évaluée, ou undefined si la chaîne ne contient aucune expression.

Si string n'est pas une chaîne (par exemple un nombre), eval() retourne l'argument sans le modifier.

Exemple d'utilisation

Dans cet exemple, nous évaluons une expression arithmétique simple et affichons le résultat :

javascript— editable

Cas d'usage pratiques d'eval()

Bien que la fonction eval() puisse être extrêmement puissante, son utilisation est souvent déconseillée en raison de problèmes de sécurité et de performance. Cependant, il existe des scénarios où eval() peut être utile.

Exécution dynamique de code

Dans les situations où du code doit être généré et exécuté dynamiquement, eval() peut être une solution pratique. Par exemple, créer une calculatrice qui évalue les saisies utilisateur comme expression mathématique :

<!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>

Parser du JSON avec eval()

Avant l'introduction de JSON.parse(), eval() était utilisé pour parser les chaînes JSON. Il est désormais recommandé d'utiliser JSON.parse() pour des raisons de sécurité.

javascript— editable

Lorsqu'on utilise eval() pour parser des chaînes JSON, il est essentiel de s'assurer que la chaîne JSON est interprétée comme une expression d'objet plutôt que comme un bloc d'instructions. Pour ce faire, la chaîne JSON est encadrée de parenthèses avant d'être passée à eval(). Cela garantit que JavaScript traite la chaîne comme une expression d'objet, évitant ainsi les erreurs de syntaxe qui pourraient survenir si la chaîne était interprétée comme un bloc d'instructions.

Info

Préférez toujours JSON.parse() à eval() pour parser du JSON. JSON.parse() n'accepte que des données, il ne peut donc jamais exécuter un script injecté.

eval() direct vs indirect et portée

La façon dont eval() voit les variables dépend de la manière dont vous l'appelez.

Un appel directeval(code) écrit littéralement — exécute le code dans la portée courante. Il peut lire et même créer des variables là où il est appelé :

javascript— editable

Un appel indirect — appeler eval via toute référence autre que le nom littéral, comme (0, eval)(code) ou en le stockant dans une variable — exécute le code dans la portée globale à la place. Il ne peut pas voir les variables locales :

javascript— editable

En mode strict, même un eval() direct obtient sa propre portée : les variables qu'il déclare ne fuient pas dans la fonction environnante. C'est une raison supplémentaire pour laquelle le code moderne a rarement besoin d'eval().

Problèmes de sécurité et de performance

L'utilisation d'eval() peut poser des risques de sécurité significatifs et des problèmes de performance. Voici pourquoi :

Risques de sécurité

eval() peut exécuter n'importe quel code JavaScript, ce qui le rend vulnérable aux attaques par injection. Un attaquant pourrait potentiellement injecter du code malveillant, entraînant de graves failles de sécurité.

Exemple de risque de sécurité :

Imaginez que vous ayez une application web qui prend des entrées utilisateur et les évalue avec eval(). Sans validation appropriée, cela peut être exploité par un attaquant pour exécuter du code malveillant.

<!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>

Dans cet exemple, si un utilisateur saisit quelque chose comme alert('Hacked!'), la fonction eval() l'exécutera, provoquant une faille de sécurité en affichant une boîte d'alerte. Un attaquant pourrait injecter du code encore plus nuisible, compromettant potentiellement l'ensemble du système.

Problèmes de performance

eval() exécute le code dans la même portée depuis laquelle il est appelé, ce qui entrave les optimisations du moteur JavaScript. Cela peut entraîner des performances plus lentes par rapport à d'autres approches.

Exemple de problème de performance :

Considérons un scénario où nous devons effectuer une série de calculs plusieurs fois. L'utilisation d'eval() pour cette tâche peut avoir un impact significatif sur les performances.

<!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>

Dans cet exemple, nous comparons les performances d'eval() avec le constructeur Function. Nous exécutons une opération arithmétique simple (3 * 4 + 5) 100 000 fois avec les deux méthodes et mesurons le temps pris par chacune.

  • Avec eval() : le code à l'intérieur d'eval() est évalué de manière répétée, ce qui est plus lent car cela empêche certaines optimisations.
  • Avec le constructeur Function : le constructeur Function crée une fonction qui effectue la même opération, mais c'est plus rapide car cela permet aux moteurs JavaScript d'optimiser l'exécution répétée.

Les résultats affichés sur la page web montrent le temps pris par chaque méthode, démontrant qu'eval() est plus lent en raison de ses problèmes de performance.

Avertissement

Évitez eval() sauf en cas d'absolue nécessité. Préférez d'abord des alternatives plus sûres : le constructeur Function pour les fonctions dynamiques, ou JSON.parse() pour les données.

Alternatives à eval()

Pour une exécution de code plus sûre et plus efficace, envisagez les alternatives suivantes :

Utiliser le constructeur Function

Le constructeur Function crée un nouvel objet fonction, similaire à eval(), mais avec une meilleure sécurité et de meilleures performances.

javascript— editable

Utiliser JSON.parse()

Pour parser des chaînes JSON, JSON.parse() est la méthode recommandée.

javascript— editable

Bonnes pratiques pour utiliser eval()

Si vous devez utiliser eval(), respectez ces bonnes pratiques pour atténuer les risques :

1. Valider les entrées

Assurez-vous que les entrées passées à eval() sont strictement validées pour éviter l'injection de code. Cela signifie n'autoriser que des caractères et expressions sûrs.

Exemple :

javascript— editable

Dans cet exemple, nous utilisons une expression régulière pour valider l'entrée utilisateur. Seuls les caractères numériques et les opérateurs arithmétiques de base sont autorisés. Si l'entrée correspond au motif, elle est évaluée avec eval(). Sinon, elle est rejetée comme invalide.

2. Utiliser try-catch

Enveloppez eval() dans un bloc try-catch pour gérer les erreurs potentielles de manière élégante. Cela évite que toute l'application ne plante si eval() rencontre une erreur.

Exemple :

javascript— editable

Ici, nous gérons les erreurs de syntaxe dans l'entrée utilisateur à l'aide d'un bloc try-catch. Si eval() lève une erreur, elle est interceptée et un message d'erreur est journalisé au lieu de faire planter l'application.

3. Restreindre la portée

Minimisez la portée des variables accessibles à eval() pour limiter les dommages potentiels d'un code malveillant. Utilisez une expression de fonction immédiatement invoquée (IIFE) pour créer une portée locale.

Exemple :

javascript— editable

Dans cet exemple, nous définissons une fonction restrictedEval à l'intérieur d'une IIFE pour créer une portée locale. Cette fonction évalue l'entrée avec eval(), mais avec des variables locales a et b définies localement. Les variables globales a et b ne sont pas accessibles, illustrant la restriction de portée.

En suivant ces bonnes pratiques, vous pouvez réduire les risques associés à l'utilisation d'eval() tout en tirant parti de ses capacités d'exécution dynamique de code lorsque cela est nécessaire.

Conclusion

La fonction eval() en JavaScript fournit un outil puissant pour l'exécution dynamique de code, mais elle s'accompagne de risques significatifs et d'inconvénients en termes de performance. En pratique, presque toute tâche qui semble nécessiter eval() a une réponse plus sûre : utilisez JSON.parse() pour les données, le constructeur Function pour les fonctions dynamiques, et des accès par objet/tableau plutôt que de construire des noms de variables à partir de chaînes. Si vous devez utiliser eval(), validez les entrées, enveloppez-la dans try...catch et réduisez sa portée au minimum.

Sujets connexes

Pratique

Pratique
Que fait la fonction eval() en JavaScript ?
Que fait la fonction eval() en JavaScript ?
Was this page helpful?