281 votes

Comment transformer une chaîne de caractères en un appel de fonction JavaScript ?

J'ai une chaîne comme :

settings.functionName + '(' + t.parentNode.id + ')';

que je veux traduire en appel de fonction comme ceci :

clickedOnItem(IdofParent);

Cela devra bien sûr être fait en JavaScript. Lorsque je fais une alerte sur settings.functionName + '(' + t.parentNode.id + ')'; il semble que tout soit correct. J'ai juste besoin d'appeler la fonction dans laquelle il serait traduit.

Légende :

settings.functionName = clickedOnItem

t.parentNode.id = IdofParent

0 votes

Quel type est settings.functionName ?

384voto

PatrikAkerstrand Points 23968

Vu que je déteste l'évaluation, et que je suis pas seul :

var fn = window[settings.functionName];
if(typeof fn === 'function') {
    fn(t.parentNode.id);
}

Editar: En réponse au commentaire de @Mahan : Dans ce cas particulier, settings.functionName serait "clickedOnItem" . Cela permettrait, au moment de l'exécution, de traduire var fn = window[settings.functionName]; en var fn = window["clickedOnItem"] qui obtiendrait une référence à function clickedOnItem (nodeId) {} . Une fois que nous avons une référence à une fonction à l'intérieur d'une variable, nous pouvons appeler cette fonction en "appelant la variable", c'est-à-dire fn(t.parentNode.id) qui est égal à clickedOnItem(t.parentNode.id) ce qui était ce que le PO voulait.

Un exemple plus complet :

/* Somewhere: */
window.settings = {
  /* [..] Other settings */
  functionName: 'clickedOnItem'
  /* , [..] More settings */
};

/* Later */
function clickedOnItem (nodeId) {
  /* Some cool event handling code here */
}

/* Even later */
var fn = window[settings.functionName]; 
/* note that settings.functionName could also be written
   as window.settings.functionName. In this case, we use the fact that window
   is the implied scope of global variables. */
if(typeof fn === 'function') {
    fn(t.parentNode.id);
}

0 votes

J'ai donné la réponse à Machine à cause de l'article. Tout le monde disait que l'Eval était la meilleure méthode, puis Machine est intervenu avec l'article qui relativise l'Eval et me fait décider de ne pas l'utiliser.

4 votes

Compte tenu de la question originale, je pense que le code "if(typeof..." n'est pas correct. Appelez simplement window[settings.functionName](t.parentNode.id). Vous obtiendrez une TypeError si la fonction n'existe pas, et c'est mieux que d'avaler silencieusement le problème et de ne rien appeler.

0 votes

Comment dois-je écrire le nom de la fonction ? juste le nom de la fonction ? ou avec le "()" ?

79voto

Fabien Ménager Points 45472
window[settings.functionName](t.parentNode.id);

Pas besoin d'un eval()

0 votes

Joli. Cela suppose, bien sûr, que la fonction n'a pas été déclarée dans une autre portée, mais même dans ce cas, j'imagine que vous pouvez le faire dans cette portée...

6 votes

Cela fonctionne si la fonction désirée est dans la portée globale, sinon, remplacez window par la portée de la fonction.

1 votes

A bien fonctionné. J'ai même utilisé moins de code que l'appel à la fonction eval.

71voto

NGauthier Points 446

Voici une façon plus générique de faire la même chose, tout en supportant les scopes :

// Get function from string, with or without scopes (by Nicolas Gauthier)
window.getFunctionFromString = function(string)
{
    var scope = window;
    var scopeSplit = string.split('.');
    for (i = 0; i < scopeSplit.length - 1; i++)
    {
        scope = scope[scopeSplit[i]];

        if (scope == undefined) return;
    }

    return scope[scopeSplit[scopeSplit.length - 1]];
}

J'espère que cela pourra aider certaines personnes.

1 votes

C'est bien, j'utilisais WinJS.Namespace.define() à portée multiple et j'ai pu appeler dynamiquement des fonctions aléatoires à partir de celui-ci grâce à vous.

0 votes

+1 pour l'avoir fait fonctionner dans n'importe quel cadre. J'utilise TypeScript, et j'ai défini "scope=this" pour accéder aux fonctions de ma classe. Cela fonctionne parfaitement !

0 votes

Ça a marché pour moi. Merci NGauthier

17voto

Andrew Hare Points 159332

JavaScript a un eval qui évalue une chaîne de caractères et l'exécute en tant que code :

eval(settings.functionName + '(' + t.parentNode.id + ')');

0 votes

Wierd - y a-t-il une raison pour laquelle ce texte a été rétrogradé ?

13 votes

Je pourrais le déclasser pour avoir utilisé l'évaluation dans une situation appropriée. Pas besoin d'évaluation ici. Il vaut mieux trouver la fonction comme une propriété d'un objet. Eval est lent et c'est un peu comme utiliser un marteau de forgeron pour écraser une mouche.

1 votes

Regardez la réponse des machines.

14voto

Jesse Millikan Points 2265

Eval() est la fonction dont vous avez besoin pour le faire, mais je vous conseille d'essayer l'une de ces choses pour minimiser l'utilisation de eval. J'espère que l'une d'entre elles aura un sens pour vous.

Enregistrez la fonction

Stockez la fonction comme une fonction, et non comme une chaîne de caractères, et utilisez-la comme une fonction plus tard. C'est vous qui décidez de l'endroit où vous stockez la fonction.

var funcForLater = clickedOnItem;

// later is now
funcForLater(t.parentNode.id);

ou

someObject.funcForLater = clickedOnItem;    
// later is now    
(someObject.funcForLater)(t.parentNode.id);

Nom de la fonction de stockage

Même si vous devez stocker le nom de la fonction sous forme de chaîne, vous pouvez minimiser la complexité en faisant

(eval(settings.functionName))(t.parentNode.id);

ce qui minimise la quantité de Javascript que vous devez construire et évaluer.

Dictionnaire des manipulateurs

Placez toutes les fonctions d'action dont vous pourriez avoir besoin dans un objet, et appelez-les à la manière d'un dictionnaire en utilisant la chaîne de caractères.

// global
itemActions = { click: clickedOnItem, rightClick: rightClickedOnItem /* etc */ };

// Later...
var actionName = "click"; // Or wherever you got the action name
var actionToDo = itemActions[actionName];
actionToDo(t.parentNode.id);

(Note mineure : si au lieu de cela vous avez utilisé la syntaxe itemActions[actionName](t.parentNode.id); alors la fonction serait appelée comme une méthode de itemActions .)

0 votes

J'ai vraiment apprécié l'approche du gestionnaire de dictionnaire - elle a très bien fonctionné pour moi - merci.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X