Comment appeler une méthode nommée dynamiquement en Javascript?

113

Je travaille sur la création dynamique de JavaScript qui sera inséré dans une page Web au fur et à mesure de sa construction.

Le JavaScript sera utilisé pour remplir un en listboxfonction de la sélection dans un autre listbox. Lorsque la sélection de l'un listboxest modifiée, il appellera un nom de méthode basé sur la valeur sélectionnée dulistbox .

Par exemple:

Listbox1 contient:

  • Colours
  • Shapes

Si Coloursest sélectionné, il appellera une populate_Coloursméthode qui en remplit une autrelistbox .

Pour clarifier ma question: comment passer cet populate_Coloursappel en JavaScript?

Chris B
la source
Je recommanderais contre cela en faveur d'avoir des succursales locales dans une seule méthode de «peuplement». Cela le rendrait plus testable et aurait l'air moins "hacky"
Aaron Powell
voir ma réponse ici. appel par son nom en javascript
Hugo R

Réponses:

208

En supposant que la populate_Coloursméthode se trouve dans l'espace de noms global, vous pouvez utiliser le code suivant, qui exploite à la fois le fait que toutes les propriétés de l'objet sont accessibles comme si l'objet était un tableau associatif et que tous les objets globaux sont en fait des propriétés de l' windowobjet hôte.

var method_name = "Colours";
var method_prefix = "populate_";

// Call function:
window[method_prefix + method_name](arg1, arg2);
Triptyque
la source
9
Merci pour la réponse. Le bit «fenêtre» m'a vraiment jeté jusqu'à ce que je le recherche sur Google et que je découvre que les objets globaux font partie de l'objet window. Maintenant c'est logique! Je vous remercie. Pour info, j'ai trouvé une bonne page à ce sujet ici devlicio.us/blogs/sergio_pereira/archive/2009/02/09/…
Chris B
3
J'ai fait quelque chose de similaire, sauf que les fonctions que je ciblais étaient dans l'espace de noms jQuery "fn". Par exemple,$.fn[method_prefix + method_name](arg1, arg2);
codecraig
1
Agréable. Cela vaut peut-être la peine d'ajouter un bloc try/ catch.
LeeGee
Cela peut être évident pour certains, mais pour ceux qui ne peuvent pas le faire fonctionner: jetez la fonction en dehors de votre code $(function () {et window.load:)
Stan Smulders
1
@peter Parce que les crochets ne sont pas des accesseurs de propriété dans ce contexte, mais désignent un tableau. Les tableaux ne sont pas des fonctions, vous ne pouvez donc pas les appeler.
user4642212
39

Comme le souligne Triptych, vous pouvez appeler n'importe quelle fonction de portée globale en la trouvant dans le contenu de l'objet hôte.

Une méthode plus propre, qui pollue beaucoup moins l'espace de noms global, consiste à placer explicitement les fonctions dans un tableau directement comme ceci:

var dyn_functions = [];
dyn_functions['populate_Colours'] = function (arg1, arg2) { 
                // function body
           };
dyn_functions['populate_Shapes'] = function (arg1, arg2) { 
                // function body
           };
// calling one of the functions
var result = dyn_functions['populate_Shapes'](1, 2);
// this works as well due to the similarity between arrays and objects
var result2 = dyn_functions.populate_Shapes(1, 2);

Ce tableau peut également être une propriété d'un objet autre que l'objet hôte global, ce qui signifie que vous pouvez créer efficacement votre propre espace de noms comme le font de nombreuses bibliothèques JS telles que jQuery. Ceci est utile pour réduire les conflits si / lorsque vous incluez plusieurs bibliothèques d'utilitaires distinctes dans la même page, et (si d'autres parties de votre conception le permettent) peut faciliter la réutilisation du code dans d'autres pages.

Vous pouvez également utiliser un objet comme celui-ci, que vous pourriez trouver plus propre:

var dyn_functions = {};
dyn_functions.populate_Colours = function (arg1, arg2) { 
                // function body
           };
dyn_functions['populate_Shapes'] = function (arg1, arg2) { 
                // function body
           };
// calling one of the functions
var result = dyn_functions.populate_Shapes(1, 2);
// this works as well due to the similarity between arrays and objects
var result2 = dyn_functions['populate_Shapes'](1, 2);

Notez qu'avec un tableau ou un objet, vous pouvez utiliser soit la méthode de paramétrage, soit l'accès aux fonctions, et vous pouvez bien sûr y stocker d'autres objets. Vous pouvez réduire davantage la syntaxe de l'une ou l'autre méthode pour un contenu qui n'est pas aussi dynamique en utilisant la notation littérale JS comme suit:

var dyn_functions = {
           populate_Colours:function (arg1, arg2) { 
                // function body
           };
         , populate_Shapes:function (arg1, arg2) { 
                // function body
           };
};

Edit: bien sûr, pour des blocs de fonctionnalités plus volumineux, vous pouvez étendre ce qui précède au "modèle de module" très courant qui est une manière populaire d'encapsuler les fonctionnalités du code de manière organisée.

David Spillett
la source
C'est une bonne façon de le garder propre. Comment pourrais-je appeler la méthode? Window [dyn_functions ['populate_Colours'] (arg1, arg2) fonctionnerait-il?
Chris B
Répondre à ma propre question - je viens de tester window [dyn_functions ['populate_Colours'] (arg1, arg2)]; et cela fonctionne vraiment.
Chris B
4
Comme le fait remarquer epascarello, vous n'avez généralement pas besoin de "window" - "dyn_functions ['populate_Colours'] (arg1, arg2);" marchera. En fait, ne pas inclure le nom de l'objet global rendra le code plus portable si vous écrivez des routines qui pourraient être utilisées dans un environnement JS autre qu'un navigateur Web. Il y a cependant une exception à cela: si vous avez une variable locale appelée dyn_functions dans une fonction, vous devez être plus spécifique à laquelle vous faites référence, mais cette situation est mieux évitée (en ayant des conventions de dénomination sensées) de toute façon.
David Spillett
1
Étant donné que cet article date de '09, vous le savez probablement déjà, mais vous créez un tableau, puis vous l'assignez aux propriétés du tableau (pas aux index). Vous pourriez aussi bien le faire var dyn_functions = {};que vous ne créez pas inutilement un tableau ... ce n'est pas un gros problème cependant.
David Sherret
réponse trop compliquée mais fonctionne. Je pense que la charge de ressources pour le scénario où j'ai une série de fonctions à motifs et j'ai besoin d'un arbre de décision pour choisir l'exécution, cette méthode peut être trop complexe pour effectuer la tâche. Mais si je câblais mon propre objet de classe, ce serait l'approche préférée pour définir l'objet lui-même.
GoldBishop
30

Je recommanderais de NE PAS utiliser global/ window/ evalà cette fin.
Au lieu de cela, faites-le de cette façon:

définir toutes les méthodes comme propriétés de Handler:

var Handler={};

Handler.application_run = function (name) {
console.log(name)
}

Maintenant appelle ça comme ça

var somefunc = "application_run";
Handler[somefunc]('jerry');

Sortie: jerry

JerryGoyal
la source
17

vous pouvez le faire comme ceci:

function MyClass() {
    this.abc = function() {
        alert("abc");
    }
}

var myObject = new MyClass();
myObject["abc"]();
Simon
la source
5

Dans un ServiceWorkerou Worker, remplacez windowpar self:

self[method_prefix + method_name](arg1, arg2);

Les ouvriers n'ont pas accès au DOM, c'est donc windowune référence invalide. L'identifiant global de portée équivalent à cet effet est self.

OXiGÈNE
la source
2

Je ne recommanderais pas d'utiliser la fenêtre comme le suggèrent certaines des autres réponses. Utilisez thiset portez en conséquence.

this['yourDynamicFcnName'](arguments);

Une autre astuce consiste à appeler dans différentes portées et à l'utiliser pour l'héritage. Disons que vous avez imbriqué la fonction et que vous souhaitez accéder à l'objet de fenêtre global. Vous pouvez faire ceci:

this['yourDynamicFcnName'].call(window, arguments);
Tim Moses
la source
1

Salut essayez ça,

 var callback_function = new Function(functionName);
 callback_function();

il gérera les paramètres lui-même.

mathi
la source
Erreur de référence non
interceptée
@brianlmerritt vous devez définir la valeur pour functionName... le répondant a fait l'hypothèse que vous aviez déjà défini cela.
GoldBishop
Il semble que la nouvelle fonction () ne puisse pas être utilisée comme ça à cette fin.
JCH77
-1

Voici une solution simple et fonctionnelle pour vérifier l' existence d'une fonction et trier cette fonction dynamiquement par une autre fonction;

Fonction de déclenchement

function runDynmicFunction(functionname){ 

    if (typeof window[functionname] == "function"  ) { //check availability

        window[functionname]("this is from the function it "); //run function and pass a parameter to it
    }
}

et vous pouvez maintenant générer la fonction dynamiquement peut-être en utilisant php comme ça

function runThis_func(my_Parameter){

    alert(my_Parameter +" triggerd");
}

maintenant vous pouvez appeler la fonction en utilisant un événement généré dynamiquement

<?php

$name_frm_somware ="runThis_func";

echo "<input type='button' value='Button' onclick='runDynmicFunction(\"".$name_frm_somware."\");'>";

?>

le code HTML exact dont vous avez besoin est

<input type="button" value="Button" onclick="runDynmicFunction('runThis_func');">
Aylian Craspa
la source
-3

Essayez avec ceci:

var fn_name = "Colours",
fn = eval("populate_"+fn_name);
fn(args1,argsN);
Gilberto
la source
Quelles sont les implications de l'utilisation de ce modèle? J'ai lu que la evalfonction avait des effets secondaires bizarres liés à son utilisation. J'essaie généralement de m'en éloigner, à moins que ce ne soit un dernier recours.
GoldBishop