Wie rufe ich eine dynamisch benannte Methode in Javascript auf?

113

Ich arbeite daran, dynamisch JavaScript zu erstellen, das beim Erstellen in eine Webseite eingefügt wird.

Das JavaScript wird verwendet, um eine listboxbasierend auf der Auswahl in einer anderen zu füllen listbox. Wenn die Auswahl von eins listboxgeändert wird, wird ein Methodenname aufgerufen, der auf dem ausgewählten Wert von basiert listbox.

Beispielsweise:

Listbox1 enthält:

  • Colours
  • Shapes

Wenn Coloursausgewählt, wird eine populate_ColoursMethode aufgerufen, die eine andere auffüllt listbox.

Um meine Frage zu klären: Wie populate_Coloursrufe ich JavaScript auf?

Chris B.
quelle
Ich würde dagegen empfehlen, lokale Zweigstellen in einer einzigen "Populate" -Methode zu haben. Es würde es testbarer machen und weniger "hacky" aussehen
Aaron Powell
siehe meine Antwort hier. Anruf mit Namen in Javascript
Hugo R

Antworten:

208

Angenommen, die populate_ColoursMethode befindet sich im globalen Namespace, können Sie den folgenden Code verwenden, der sowohl ausnutzt, dass auf alle Objekteigenschaften zugegriffen werden kann, als ob das Objekt ein assoziatives Array wäre, als auch dass alle globalen Objekte tatsächlich Eigenschaften des windowHostobjekts sind.

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

// Call function:
window[method_prefix + method_name](arg1, arg2);
Triptychon
quelle
9
Danke für die Antwort. Das 'Fenster'-Bit hat mich wirklich geworfen, bis ich es gegoogelt habe und festgestellt habe, dass globale Objekte Teil des Fensterobjekts sind. Jetzt macht es Sinn! Danke dir. Zu Ihrer Information,
Chris B
3
Ich habe etwas Ähnliches gemacht, außer dass die Funktionen, auf die ich abzielte, im jQuery-Namespace "fn" waren. Zum Beispiel$.fn[method_prefix + method_name](arg1, arg2);
Codecraig
1
Nett. Vielleicht lohnt es sich, einen try/ catchBlock hinzuzufügen .
LeeGee
Dies mag für einige offensichtlich sein, aber für diejenigen, die es nicht zum Laufen bringen können: Werfen Sie die Funktion außerhalb Ihrer $(function () {und window.loadCode :)
Stan Smulders
1
@peter Da eckige Klammern in diesem Zusammenhang keine Eigenschaftszugriffsberechtigten sind, sondern ein Array bezeichnen. Arrays sind keine Funktionen, daher können Sie sie nicht aufrufen.
user4642212
39

Wie Triptychon hervorhebt, können Sie jede globale Bereichsfunktion aufrufen, indem Sie sie im Inhalt des Hostobjekts finden.

Eine sauberere Methode, die den globalen Namespace viel weniger verschmutzt, besteht darin, die Funktionen explizit wie folgt explizit in ein Array einzufügen:

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);

Dieses Array kann auch eine Eigenschaft eines anderen Objekts als des globalen Hostobjekts sein, was bedeutet, dass Sie effektiv Ihren eigenen Namespace erstellen können, wie dies bei vielen JS-Bibliotheken wie jQuery der Fall ist. Dies ist nützlich, um Konflikte zu reduzieren, wenn Sie mehrere separate Dienstprogrammbibliotheken auf derselben Seite einfügen und (sofern andere Teile Ihres Entwurfs dies zulassen) die Wiederverwendung des Codes auf anderen Seiten erleichtern.

Sie können auch ein Objekt wie dieses verwenden, das Sie möglicherweise sauberer finden:

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);

Beachten Sie, dass Sie mit einem Array oder einem Objekt entweder die Methode zum Festlegen oder Zugreifen auf die Funktionen verwenden und natürlich auch andere Objekte darin speichern können. Sie können die Syntax beider Methoden für nicht so dynamische Inhalte weiter reduzieren, indem Sie die JS-Literalnotation wie folgt verwenden:

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

Bearbeiten: Natürlich können Sie für größere Funktionsblöcke das Obige auf das sehr verbreitete "Modulmuster" erweitern, das eine beliebte Methode ist, um Code-Features auf organisierte Weise zu kapseln.

David Spillett
quelle
Das ist eine schöne Art, es sauber zu halten. Wie würde ich die Methode aufrufen? Würde window [dyn_functions ['populate_Colours'] (arg1, arg2) funktionieren?
Chris B
Beantwortung meiner eigenen Frage - Ich habe gerade window [dyn_functions ['populate_Colours'] (arg1, arg2)] getestet. und es funktioniert tatsächlich.
Chris B.
4
Wie epascarello betont, benötigen Sie normalerweise kein "Fenster" - "dyn_functions ['populate_Colours'] (arg1, arg2);" wird funktionieren. Wenn Sie den Namen des globalen Objekts nicht angeben, wird der Code portabler, wenn Sie Routinen schreiben, die möglicherweise jemals in einer anderen JS-Umgebung als einem Webbrowser verwendet werden. Es gibt jedoch eine Ausnahme: Wenn Sie eine lokale Variable namens dyn_functions in einer Funktion haben, müssen Sie spezifischer sein, auf die Sie sich beziehen, aber diese Situation wird am besten vermieden (durch sinnvolle Namenskonventionen).
David Spillett
1
Da dieser Beitrag aus dem Jahr '09 stammt, wissen Sie dies wahrscheinlich bereits, aber Sie erstellen ein Array und weisen es dann den Eigenschaften des Arrays zu (nicht den Indizes). Sie können dies auch tun var dyn_functions = {};, um nicht unnötig ein Array zu erstellen. Dies ist jedoch kein großes Problem.
David Sherret
übermäßig komplizierte Antwort, funktioniert aber. Ich würde denken, dass die Ressourcenlast für Szenarien, in denen ich eine Reihe von strukturierten Funktionen habe und einen Entscheidungsbaum benötige, um die Ausführung auszuwählen, diese Methode möglicherweise zu komplex ist, um die Aufgabe auszuführen. Wenn ich jedoch mein eigenes Klassenobjekt verkabeln würde, wäre dies der bevorzugte Ansatz, um das Objekt selbst zu definieren.
GoldBishop
30

Ich würde empfehlen , / / NICHT für diesen Zweck zu verwenden. Gehen Sie stattdessen folgendermaßen vor: globalwindoweval

Definieren Sie alle Methoden als Eigenschaften von Handler:

var Handler={};

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

Nennen Sie es jetzt so

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

Ausgabe: Jerry

JerryGoyal
quelle
17

Sie können es so machen:

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

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

Innerhalb eines ServiceWorkeroder Workerdurch ersetzen windowdurch self:

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

Arbeiter haben keinen Zugriff auf das DOM, daher windowist dies eine ungültige Referenz. Die entsprechende globale Bereichskennung für diesen Zweck lautet self.

SAUERSTOFF
quelle
2

Ich würde nicht empfehlen, das Fenster zu verwenden, wie einige der anderen Antworten vermuten lassen. Verwendung thisund Umfang entsprechend.

this['yourDynamicFcnName'](arguments);

Ein weiterer guter Trick besteht darin, innerhalb verschiedener Bereiche aufzurufen und ihn für die Vererbung zu verwenden. Angenommen, Sie haben die Funktion verschachtelt und möchten Zugriff auf das globale Fensterobjekt. Sie könnten dies tun:

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

Hallo versuch das,

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

Es wird die Parameter selbst behandeln.

Mathi
quelle
nicht erfasster Referenzfehler - Funktionsname ist nicht definiert
brianlmerritt
@brianlmerritt Sie müssen den Wert definieren für functionName... der Antwortende ging davon aus, dass Sie diesen bereits definiert hatten.
GoldBishop
Es scheint, dass new Function () für diesen Zweck nicht so verwendet werden kann.
JCH77
-1

Hier ist eine funktionierende und einfache Lösung, um das Vorhandensein einer Funktion zu überprüfen und diese Funktion dynamisch zu testen durch eine andere Funktion zu .

Auslöserfunktion

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

und Sie können die Funktion jetzt dynamisch generieren, möglicherweise mit PHP wie diesem

function runThis_func(my_Parameter){

    alert(my_Parameter +" triggerd");
}

Jetzt können Sie die Funktion mit einem dynamisch generierten Ereignis aufrufen

<?php

$name_frm_somware ="runThis_func";

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

?>

Der genaue HTML-Code, den Sie benötigen, ist

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

Versuchen Sie es damit:

var fn_name = "Colours",
fn = eval("populate_"+fn_name);
fn(args1,argsN);
Gilberto
quelle
Welche Auswirkungen hat die Verwendung dieses Musters? Ich habe gelesen, dass die evalFunktion einige seltsame Nebenwirkungen im Zusammenhang mit ihrer Verwendung hat. Ich versuche im Allgemeinen, mich davon fernzuhalten, es sei denn, es ist ein letzter Ausweg.
GoldBishop