[ Web Proxy ]
URL:
Viewing: https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Global_Objects/eval [Back]  [Original]

eval() - JavaScript | MDN

Cette page a t traduite partir de l'anglais par la communaut. Vous pouvez contribuer en rejoignant la communaut francophone sur MDN Web Docs.

View in English Always switch to English

eval()

Baseline Large disponibilit

Cette fonctionnalit est bien tablie et fonctionne sur de nombreux appareils et versions de navigateurs. Elle est disponible sur tous les navigateurs depuis juillet 2015.

Attention : L'argument transmis cette fonction est analys dynamiquement et excut comme du JavaScript. Les API de ce type sont appeles points d'injection et peuvent tre une source potentielle d'attaques par injection de script inter-sites (XSS).

Vous pouvez rduire ce risque en transmettant toujours des objets TrustedScript au lieu de chanes de caractres et en imposant des types de confiance.

Voir Considrations de scurit pour plus d'informations.

La fonction eval() value du code JavaScript reprsent sous forme de chane de caractres et retourne sa valeur de terminaison. La source est analyse comme un script.

Dans cet article

Exemple interactif

console.log(eval("2 + 2"));
// Rsultat attendu : 4

console.log(eval(new String("2 + 2")));
// Rsultat attendu : 2 + 2

console.log(eval("2 + 2") === eval("4"));
// Rsultat attendu : true

console.log(eval("2 + 2") === eval(new String("2 + 2")));
// Rsultat attendu : false

Syntaxe

js
eval(script)

Paramtres

script

Une instance de TrustedScript ou une chane de caractres reprsentant une expression JavaScript, une instruction ou une suite d'instructions JavaScript. L'expression peut inclure des variables et des proprits d'objets existants. Elle sera analyse comme un script, donc les dclarations import (qui ne peuvent exister que dans des modules) ne sont pas autorises.

Valeur de retour

La valeur de terminaison du code valu. Si la valeur de terminaison est vide, undefined est retourne. Si script n'est pas une instance de TrustedScript ou une chane de caractres primitive, eval() retourne l'argument inchang.

Exceptions

SyntaxError

Le paramtre script ne peut pas tre analys comme un script.

TypeError

script est une chane de caractres lorsque les types de confiance sont imposs par une CSP et qu'aucune politique par dfaut n'est dfinie.

La mthode lance galement toute exception qui survient lors de l'valuation du code.

Description

eval() est une proprit de fonction de l'objet global.

L'argument de la fonction eval() est une chane de caractres. Elle value la chanes de caractres source comme un corps de script, ce qui signifie que les instructions et les expressions sont autorises. Elle retourne la valeur de fin du code. Pour les expressions, il s'agit de la valeur laquelle l'expression est value. De nombreuses instructions et dclarations ont galement des valeurs de fin, mais le rsultat peut tre surprenant (par exemple, la valeur de fin d'une affectation est la valeur affecte, mais la valeur de fin de let est indfinie), il est donc recommand de ne pas se fier aux valeurs de fin des instructions.

En mode strict, dclarer une variable nomme eval ou rassigner eval est une erreur de syntaxe (SyntaxError).

js
"use strict";

const eval = 1; // SyntaxError: Unexpected eval or arguments in strict mode

Si l'argument de eval() n'est pas une instance de TrustedScript ou une chane de caractres primitive, eval() retourne l'argument inchang. Dans l'exemple suivant, passer un objet String au lieu d'une chane primitive fait que eval() retourne l'objet String au lieu d'valuer la chane.

js
eval(new String("2 + 2")); // retourne un objet String contenant "2 + 2"
eval("2 + 2"); // retourne 4

Pour contourner ce comportement de faon gnrique, vous pouvez contraindre l'argument en chane de caractres vous-mme avant de le passer dans eval().

js
const expression = new String("2 + 2");
eval(String(expression)); // retourne 4

valuation directe et indirecte

Il existe deux modes d'appel de eval() : l'valuation directe et l'valuation indirecte.L'valuation directe, comme son nom l'indique, fait rfrence l'appel direct de la fonction globale eval avec eval(). Tout le reste, y compris l'invocation l'aide d'une variable alias, l'aide d'un accs membre ou d'une autre expression, ou l'aide de l'oprateur de chanage optionnel ?., est indirect.

js
// Appel direct
eval("x + y");

// Appel indirect utilisant l'oprateur virgule pour retourner eval
(0, eval)("x + y");

// Appel indirect via le chanage optionnel
eval?.("x + y");

// Appel indirect utilisant une variable pour stocker et retourner eval
const myEval = eval;
myEval("x + y");

// Appel indirect via l'accs aux membres
const obj = { eval };
obj.eval("x + y");

L'valuation indirecte peut tre vue comme si le code tait valu dans une balise <script> spare. Cela signifie :

  • L'valuation indirecte fonctionne dans le contexte global plutt que dans le contexte local, et le code valu n'a pas accs aux variables locales dans le contexte o il est appel.

    js
    function test() {
      const x = 2;
      const y = 4;
      // Appel direct, utilise le contexte local
      console.log(eval("x + y")); // Le rsultat est 6
      // Appel indirect, utilise le contexte global
      console.log(eval?.("x + y")); // Lve une erreur car x n'est pas dfini dans le contexte global
    }
    
  • Un eval indirect n'hrite pas de la rigueur du contexte environnant, et n'est en mode strict que si la chane source elle-mme contient une directive "use strict".

    js
    function nonStrictContext() {
      eval?.(`with (Math) console.log(PI);`);
    }
    function strictContext() {
      "use strict";
      eval?.(`with (Math) console.log(PI);`);
    }
    function strictContextStrictEval() {
      "use strict";
      eval?.(`"use strict"; with (Math) console.log(PI);`);
    }
    nonStrictContext(); // Affiche 3.141592653589793
    strictContext(); // Affiche 3.141592653589793
    strictContextStrictEval(); // Uncaught SyntaxError: Strict mode code may not include a with statement
    

    En revanche, l'valuation directe hrite de la rigueur du contexte appelant.

    js
    function nonStrictContext() {
      eval(`with (Math) console.log(PI);`);
    }
    function strictContext() {
      "use strict";
      eval(`with (Math) console.log(PI);`);
    }
    function strictContextStrictEval() {
      "use strict";
      eval(`"use strict"; with (Math) console.log(PI);`);
    }
    nonStrictContext(); // Affiche 3.141592653589793
    strictContext(); // Uncaught SyntaxError: Strict mode code may not include a with statement
    strictContextStrictEval(); // Uncaught SyntaxError: Strict mode code may not include a with statement
    
  • Les variables dclares avec var et les dclarations de fonction seraient places dans la porte environnante si la chane de caractres source n'tait pas interprte en mode strict pour l'valuation indirecte, elles deviennent des variables globales. S'il s'agit d'une valuation directe dans un contexte en mode strict, ou si la chane de caractres source eval elle-mme est en mode strict, alors les dclarations var et les dclarations de fonction ne  fuient  pas dans la porte environnante.

    js
    // Ni le contexte ni la chane de caractres source ne sont stricts,
    // donc var cre une variable dans la porte environnante.
    eval("var a = 1;");
    console.log(a); // 1
    // Le contexte n'est pas strict, mais la source eval est stricte,
    // donc b est limit au script valu.
    eval("'use strict'; var b = 1;");
    console.log(b); // ReferenceError: b is not defined
    
    function strictContext() {
      "use strict";
      // Le contexte est strict, mais ceci est indirect et la chane source
      // n'est pas stricte, donc c est toujours global
      eval?.("var c = 1;");
      // valuation directe dans un contexte strict, donc d est limit
      eval("var d = 1;");
    }
    strictContext();
    console.log(c); // 1
    console.log(d); // ReferenceError: d is not defined
    

    Les dclarations let et const l'intrieur de la chane value sont toujours limites ce script.

  • L'valuation directe peut avoir accs des expressions contextuelles supplmentaires. Par exemple, dans le corps d'une fonction, on peut utiliser new.target:

    js
    function Ctor() {
      eval("console.log(new.target)");
    }
    new Ctor(); // [Function: Ctor]
    

Ne jamais utiliser eval() directement !

L'utilisation directe de eval() prsente plusieurs problmes :

  • eval() excute le code qui lui est pass avec les privilges de l'appelant. Si vous excutez eval() avec une chane de caractres qui pourrait tre affecte par une partie malveillante, vous pourriez finir par excuter du code malveillant sur la machine de l'utilisateurice avec les permissions de votre page Web / extension. Plus important encore, permettre du code tiers d'accder la porte dans laquelle eval() a t invoqu (si c'est un eval direct) peut entraner des attaques possibles qui lisent ou modifient les variables locales. Voir Considrations de scurit pour des approches qui attnuent ces risques.
  • eval() est plus lent que les autres solutions, car il doit invoquer l'interprteur JavaScript, alors que de nombreuses autres constructions sont optimises par les moteurs JS modernes.
  • Les interprteurs JavaScript modernes convertissent le JavaScript en code machine Cela signifie que tout concept de nommage de variable est supprim. Ainsi, toute utilisation de eval() obligera le navigateur effectuer de longues et coteuses recherches de noms de variables pour dterminer o la variable existe dans le code machine et dfinir sa valeur. De plus, de nouveaux lments peuvent tre introduits dans cette variable grce eval(), comme la modification du type de cette variable, ce qui oblige le navigateur rvaluer tout le code machine gnr pour compenser.
  • Les minificateurs renoncent toute minification si la porte dpend de manire transitive de eval(), car sinon eval() ne peut pas lire la variable correcte l'excution.

Il existe de nombreux cas o l'utilisation de eval() ou de mthodes associes peut tre optimise, voire vite.

Utiliser la fonction eval() indirectement

Considrez ce code :

js
function looseJsonParse(obj) {
  return eval(`(${obj})`);
}
console.log(looseJsonParse("{ a: 4 - 1, b: function () {}, c: new Map() }"));

Le simple fait d'utiliser une valuation indirecte et d'imposer le mode strict peut considrablement amliorer le code :

js
function looseJsonParse(obj) {
  return eval?.(`"use strict";(${obj})`);
}
console.log(looseJsonParse("{ a: 4 - 1, b: function () {}, c: new Map() }"));

Les deux extraits de code ci-dessus peuvent sembler fonctionner de la mme manire, mais ce n'est pas le cas ; le premier, qui utilise une valuation directe, prsente plusieurs problmes.

  • Il est beaucoup plus lent, en raison de nombreuses inspections de porte. Remarquez c: new Map() dans la chane de caractres value. Dans la version avec valuation indirecte, l'objet est valu dans la porte globale, il est donc sr pour l'interprteur de supposer que Map fait rfrence au constructeur global Map() au lieu d'une variable locale appele Map. Cependant, dans le code utilisant l'valuation directe, l'interprteur ne peut pas supposer cela. Par exemple, dans le code suivant, Map dans la chane de caractres value ne fait pas rfrence window.Map().

    js
    function looseJsonParse(obj) {
      class Map {}
      return eval(`(${obj})`);
    }
    console.log(looseJsonParse(`{ a: 4 - 1, b: function () {}, c: new Map() }`));
    

    Ainsi, dans la version eval() du code, le navigateur est contraint d'effectuer un appel de recherche coteux pour vrifier s'il existe des variables locales appeles Map().

  • Si vous n'utilisez pas le mode strict, les dclarations var dans la source eval() deviennent des variables dans la porte environnante. Cela entrane des problmes difficiles dboguer si la chane de caractres est acquise partir d'une entre externe, en particulier s'il existe dj une variable portant le mme nom.

  • L'valuation directe peut lire et modifier les liaisons dans la porte environnante, ce qui peut entraner la corruption des donnes locales par des entres externes.

  • Lors de l'utilisation directe de eval, en particulier lorsque la source d'valuation ne peut pas tre prouve comme tant en mode strict, le moteur et les outils de compilation doivent dsactiver toutes les optimisations lies la mise en ligne (inlining en anglais), car la source eval() peut dpendre de n'importe quel nom de variable dans son champ d'application environnant.

Cependant, l'utilisation indirecte de eval() ne permet pas de passer des liaisons supplmentaires autres que les variables globales existantes pour que la source value puisse les lire. Si vous devez dfinir des variables supplmentaires auxquelles la source value doit avoir accs, envisagez d'utiliser le constructeur Function().

Utiliser le constructeur Function()

Le constructeur Function() est trs similaire l'exemple d'valuation indirecte ci-dessus : il value galement le code JavaScript qui lui est pass dans la porte globale sans lire ni modifier les liaisons locales, ce qui permet aux moteurs d'effectuer plus d'optimisations que l'valuation directe avec eval().

La diffrence entre eval() et Function() rside dans le fait que la chane de caractres source transmise Function() est analyse comme un corps de fonction, et non comme un script. Il existe quelques nuances par exemple, vous pouvez utiliser des instructions return au niveau suprieur d'un corps de fonction, mais pas dans un script.

Le constructeur Function() est utile si vous souhaitez crer des liaisons locales dans votre source value, en passant les variables comme paramtres.

js
function add(a, b) {
  return a + b;
}
function runCodeWithAddFunction(obj) {
  return Function("add", `"use strict";return (${obj});`)(add);
}
console.log(runCodeWithAddFunction("add(5, 7)")); // 12

Les fonctions eval() et Function() valuent implicitement du code arbitraire et sont interdites dans les paramtres stricts CSP. Il existe galement des alternatives plus sres (et plus rapides !) eval() ou Function() pour les cas d'utilisation courants.

Utiliser les accesseurs par crochet

Vous ne devez pas utiliser eval() pour accder dynamiquement aux proprits. Prenons l'exemple suivant, o la proprit de l'objet laquelle il faut accder n'est connue qu'au moment o le code est excut. Cela peut tre fait avec eval() :

js
const obj = { a: 20, b: 30 };
const propName = getPropName(); // retourne "a" ou "b"

const result = eval(`obj.${propName}`);

Cependant, eval() n'est pas ncessaire ici en fait, il est plus sujet aux erreurs, car si propName n'est pas un identifiant valide, cela entrane une erreur de syntaxe. De plus, si getPropName n'est pas une fonction que vous contrlez, cela peut entraner l'excution de code arbitraire. la place, utilisez les accesseurs de proprits, qui sont beaucoup plus rapides et srs :

js
const obj = { a: 20, b: 30 };
const propName = getPropName(); // retourne "a" ou "b"
const result = obj[propName]; // obj["a"] quivaut  obj.a

Vous pouvez mme utiliser cette mthode pour accder aux proprits descendantes. Avec eval(), cela ressemblerait ceci :

js
const obj = { a: { b: { c: 0 } } };
const propPath = getPropPath(); // suppose que cela retourne "a.b.c"

const result = eval(`obj.${propPath}`); // 0

viter eval() ici peut tre fait en divisant le chemin de la proprit et en parcourant les diffrentes proprits :

js
function getDescendantProp(obj, desc) {
  const arr = desc.split(".");
  while (arr.length) {
    obj = obj[arr.shift()];
  }
  return obj;
}

const obj = { a: { b: { c: 0 } } };
const propPath = getPropPath(); // suppose que cela retourne "a.b.c"
const result = setDescendantProp(obj, propPath); // 0

Dfinir une proprit de cette manire fonctionne de manire similaire :

js
function setDescendantProp(obj, desc, value) {
  const arr = desc.split(".");
  while (arr.length > 1) {
    obj = obj[arr.shift()];
  }
  return (obj[arr[0]] = value);
}

const obj = { a: { b: { c: 0 } } };
const propPath = getPropPath(); // suppose que cela retourne "a.b.c"
const result = setDescendantProp(obj, propPath, 1); // obj.a.b.c vaut dsormais 1

Cependant, sachez que l'utilisation d'accesseurs entre crochets avec une entre non contrainte n'est pas non plus sre : cela peut entraner des attaques par injection d'objet (angl.).

Utiliser les fonctions de rappel

JavaScript dispose de fonctions de premire classe, ce qui signifie que vous pouvez passer des fonctions en tant qu'arguments d'autres API, les stocker dans des variables et des proprits d'objets, etc. De nombreuses API DOM sont conues dans cette optique, vous pouvez (et devriez) donc crire :

js
// Au lieu de setTimeout("", 1000) utilisez :
setTimeout(() => {
  // 
}, 1000);

// Au lieu de elt.setAttribute("onclick", "") utilisez :
elt.addEventListener("click", () => {
  // 
});

Les closures sont galement utiles pour crer des fonctions paramtres sans concatner des chanes de caractres.

Utiliser JSON

Si la chane de caractres sur laquelle vous appelez eval() contient des donnes (par exemple, un tableau : "[1, 2, 3]"), par opposition du code, vous devriez envisager de passer JSON, qui permet la chane de caractres d'utiliser un sous-ensemble de la syntaxe JavaScript pour reprsenter les donnes.

Notez que, la syntaxe JSON tant plus limite que celle de JavaScript, de nombreux littraux JavaScript valides ne seront pas analyss en tant que JSON. Par exemple, les virgules finales ne sont pas autorises en JSON, et les noms de proprits (cls) dans les littraux d'objet doivent tre placs entre guillemets. Veillez utiliser un srialiseur JSON pour gnrer des chanes de caractres qui seront ensuite analyses en tant que JSON.

Il est gnralement prfrable de transmettre des donnes soigneusement contrles plutt que du code arbitraire. Par exemple, une extension conue pour extraire le contenu de pages Web pourrait dfinir ses rgles d'extraction dans XPath plutt que dans du code JavaScript.

Considrations de scurit

Cette mthode peut tre utilise pour excuter une entre arbitraire avec les privilges de l'appelant. Si l'entre est une chane de caractres potentiellement dangereuse fournie par une utilisateurice, cela constitue un vecteur possible pour des attaques de par script inter-site (XSS).

Par exemple, le code suivant montre comment eval() pourrait excuter codeMailveillant fourni par une utilisateurice :

js
const codeMailveillant = "alert('Code potentiellement malveillant !');";
const vipere = eval(codeMailveillant);

Les sites web dots d'une politique de scurit du contenu (CSP) qui dfinissent script-src ou default-src empcheront l'excution de ce code par dfaut. Si vous devez autoriser l'excution des scripts via eval(), vous pouvez attnuer les risques en affectant toujours une instance de TrustedScript au lieu d'une chane de caractres, et en imposant les types de confiance l'aide de la directive CSP require-trusted-types-for. Cela garantit que l'entre est passe par une fonction de transformation.

Pour permettre l'excution de eval(), vous devez galement dfinir le mot-cl trusted-types-eval dans votre directive CSP script-src. Le mot-cl unsafe-eval permet galement eval(), mais est beaucoup moins sr que trusted-types-eval car il permettrait l'excution mme sur les navigateurs qui ne prennent pas en charge les types de confiance.

Par exemple, la CSP requise pour votre site pourrait ressembler ceci :

http
Content-Security-Policy: require-trusted-types-for 'script'; script-src '<your_allowlist>' 'trusted-types-eval'

Le comportement de la fonction de transformation implmente dans votre politique de types de confiance dpend du cas d'utilisation spcifique qui ncessite un script fourni par l'utilisateurice. Si possible, vous devez verrouiller les scripts autoriss sur le code exact que vous acceptez d'excuter. Si cela n'est pas possible, vous pouvez autoriser ou bloquer l'utilisation de certaines fonctions dans l'entre fournie.

Exemples

Notez que le premier exemple montre comment utiliser la mthode avec les types de confiance. Les autres exemples omettent cette tape pour plus de concision.

Utiliser TrustedScript

Pour attnuer le risque de XSS, il faut toujours affecter des instances de TrustedScript au paramtre script. Il faut galement le faire si vous imposez les types de confiance pour d'autres raisons et souhaitez autoriser certaines sources de scripts permises (par CSP: script-src).

Les types de confiance ne sont pas encore pris en charge sur tous les navigateurs, donc nous dfinissons d'abord le prothse minimale de Trusted Types. Cela agit comme un remplacement transparent pour l'API JavaScript Trusted Types :

js
if (typeof trustedTypes === "undefined")
  trustedTypes = { createPolicy: (n, rules) => rules };

Ensuite, nous crons un TrustedTypePolicy qui dfinit une mthode createScript() pour transformer des chanes de caractres en instances de TrustedScript.

Dans cet exemple, nous supposons que vous disposez d'une fonction transformedScript() qui dfinit votre logique de transformation/filtrage.

js
const policy = trustedTypes.createPolicy("script-policy", {
  createScript(input) {
    const transformed = transformedScript(input); // Notre mthode de filtrage
    return transformed;
  },
});

Ensuite, nous utilisons l'objet policy pour crer un objet TrustedScript partir d'une chane de caractres potentiellement non sre :

js
// La chane de caractres potentiellement malveillante
const untrustedScript = "alert('Code potentiellement malveillant !');";

// Crer une instance TrustedScriptURL  l'aide de la politique
const trustedScript = policy.createScript(untrustedScript);

L'objet TrustedScript peut maintenant tre transmis eval() :

js
eval(trustedScript);

Utiliser la fonction eval()

Dans le code suivant, les deux instructions contenant eval() retournent 42. La premire value la chane de caractres "x + y + 1" ; la seconde value la chane de caractres "42".

js
const x = 2;
const y = 39;
const z = "42";
eval("x + y + 1"); // 42
eval(z); // 42

eval() retourne la valeur de compltion des instructions

eval() retourne la valeur de compltion des instructions. Pour if, ce serait la dernire expression ou instruction value.

js
const str = "if (a) { 1 + 1 } else { 1 + 2 }";
let a = true;
let b = eval(str);

console.log(`b vaut : ${b}`); // b vaut : 2

a = false;
b = eval(str);

console.log(`b vaut : ${b}`); // b vaut : 3

L'exemple suivant utilise eval() pour valuer la chane de caractres str. Cette chane de caractres consiste en des instructions JavaScript qui affectent z la valeur de 42 si x vaut cinq, et 0 sinon. Lorsque la seconde instruction est excute, eval() entranera l'excution des instructions, les instructions seront values et la valeur de z sera donc retourne, car la valeur de compltion d'une affectation est la valeur affecte.

js
const x = 5;
const str = `if (x === 5) {
  console.log("z is 42");
  z = 42;
} else {
  z = 0;
}`;

console.log("z is ", eval(str)); // z is 42  z is 42

Si vous affectez plusieurs valeurs, la dernire valeur est retourne.

js
let x = 5;
const str = `if (x === 5) {
  console.log("z vaut 42");
  z = 42;
  x = 420;
} else {
  z = 0;
}`;

console.log("x vaut", eval(str)); // z vaut 42  x vaut 420

Utiliser eval() pour dfinir une fonction sous forme de chane de caractres ncessite ( et ) en prfixe et suffixe

js
// C'est une dclaration de fonction
const fctStr1 = "function a() {}";
// C'est une expression de fonction
const fctStr2 = "(function b() {})";
const fct1 = eval(fctStr1); // retourne undefined mais `a` est maintenant disponible comme une fonction globale
const fct2 = eval(fctStr2); // retourne une function `b`

Spcifications

Spcification
ECMAScript 2027 LanguageSpecification
# sec-eval-x

Compatibilit des navigateurs

Voir aussi


Web Proxy Viewer  |  New URL  |  Original Page