Jak wywołać metodę o nazwie dynamicznej w JavaScript?

113

Pracuję nad dynamicznym utworzeniem kodu JavaScript, który zostanie wstawiony do strony internetowej w trakcie jej tworzenia.

JavaScript zostanie użyty do wypełnienia na listboxpodstawie wyboru w innym listbox. Gdy wybór jednej listboxzostanie zmieniony, wywoła ona nazwę metody na podstawie wybranej wartości listbox.

Na przykład:

Listbox1 zawiera:

  • Colours
  • Shapes

Jeśli Coloursjest zaznaczone, wywoła populate_Coloursmetodę, która zapełni inną listbox.

Aby wyjaśnić moje pytanie: jak wykonać to populate_Colourswywołanie w JavaScript?

Chris B.
źródło
Odradzałbym to na korzyść lokalnych oddziałów w jednej metodzie „wypełniania”. To uczyniłoby go bardziej testowalnym i wyglądałby mniej „hacky”
Aaron Powell
zobacz moją odpowiedź tutaj. zadzwoń po imieniu w javascript
Hugo R

Odpowiedzi:

208

Zakładając, że populate_Coloursmetoda znajduje się w globalnej przestrzeni nazw, możesz użyć następującego kodu, który wykorzystuje zarówno to, że wszystkie właściwości obiektu mogą być dostępne, jakby obiekt był tablicą asocjacyjną, jak i że wszystkie obiekty globalne są w rzeczywistości właściwościami windowobiektu hosta.

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

// Call function:
window[method_prefix + method_name](arg1, arg2);
Tryptyk
źródło
9
Dzięki za odpowiedzi. Bit „window” naprawdę mnie wyrzucił, dopóki go nie wygooglowałem i nie odkryłem, że obiekty globalne są częścią obiektu okna. Teraz to ma sens! Dziękuję Ci. FYI Znalazłem dobrą stronę o tym tutaj devlicio.us/blogs/sergio_pereira/archive/2009/02/09/…
Chris B
3
Zrobiłem coś podobnego, z wyjątkiem funkcji, do których dążyłem, w przestrzeni nazw jQuery „fn”. Na przykład$.fn[method_prefix + method_name](arg1, arg2);
codecraig
1
Miły. Być może warto dodać try/ catchblok.
LeeGee,
Dla niektórych może to być oczywiste, ale dla tych, którzy nie mogą jej uruchomić: wyrzuć funkcję poza swój $(function () {i window.loadzakoduj :)
Stan Smulders
1
@peter Ponieważ nawiasy kwadratowe nie są metodami dostępu do właściwości w tym kontekście, ale oznaczają tablicę. Tablice nie są funkcjami, więc nie możesz ich wywoływać.
user4642212
39

Jak wskazuje Triptych, możesz wywołać dowolną funkcję zasięgu globalnego, znajdując ją w zawartości obiektu hosta.

Czystszą metodą, która znacznie mniej zanieczyszcza globalną przestrzeń nazw, jest jawne umieszczenie funkcji w tablicy bezpośrednio, tak jak pokazano poniżej:

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

Ta tablica może również być właściwością jakiegoś obiektu innego niż globalny obiekt hosta, co oznacza, że ​​możesz efektywnie tworzyć własną przestrzeń nazw, tak jak robi to wiele bibliotek JS, takich jak jQuery. Jest to przydatne do zmniejszania konfliktów, jeśli / kiedy umieścisz wiele oddzielnych bibliotek narzędzi na tej samej stronie i (jeśli pozwalają na to inne części projektu), może ułatwić ponowne użycie kodu na innych stronach.

Możesz również użyć obiektu takiego jak ten, który może okazać się czystszy:

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

Zauważ, że w przypadku tablicy lub obiektu możesz użyć dowolnej metody ustawiania lub dostępu do funkcji i oczywiście możesz tam również przechowywać inne obiekty. Możesz dodatkowo zmniejszyć składnię obu metod w przypadku treści, które nie są tak dynamiczne, używając notacji literału JS, jak pokazano poniżej:

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

Edycja: oczywiście w przypadku większych bloków funkcjonalności możesz rozszerzyć powyższe do bardzo powszechnego „wzorca modułu”, który jest popularnym sposobem hermetyzacji funkcji kodu w zorganizowany sposób.

David Spillett
źródło
To dobry sposób na utrzymanie go w czystości. Jak jednak nazwałbym tę metodę? Czy okno [dyn_functions ['populate_Colours'] (arg1, arg2) zadziała?
Chris B
Odpowiadając na własne pytanie - właśnie przetestowałem okno [dyn_functions ['populate_Colours'] (arg1, arg2)]; i rzeczywiście działa.
Chris B
4
Jak wskazuje epascarello, zwykle nie potrzebujesz "window" - "dyn_functions ['populate_Colours'] (arg1, arg2);" będzie działać. W rzeczywistości brak nazwy obiektu globalnego sprawi, że kod będzie bardziej przenośny, jeśli piszesz procedury, które mogą być kiedykolwiek używane w środowisku JS innym niż przeglądarka internetowa. Jest jednak wyjątek od tej reguły: jeśli masz lokalną zmienną o nazwie dyn_functions w funkcji, musisz być bardziej szczegółowy, do którego się odnosisz, ale i tak najlepiej tego unikać (stosując rozsądne konwencje nazewnictwa).
David Spillett
1
Ponieważ ten post pochodzi z '09, prawdopodobnie już o tym wiesz, ale tworzysz tablicę, a następnie przypisujesz jej właściwości (nie indeksy). Równie dobrze var dyn_functions = {};możesz to zrobić, aby niepotrzebnie nie tworzyć tablicy ... nie jest to jednak duży problem.
David Sherret
zbyt skomplikowana odpowiedź, ale działa. Wydaje mi się, że obciążenie zasobów dla scenariusza, w którym mam szereg funkcji wzorzystych i potrzebuję drzewa decyzyjnego, aby wybrać wykonanie, ta metoda może być zbyt złożona, aby wykonać zadanie. Jednak gdybym okablował swój własny obiekt klasy, byłoby to preferowane podejście do definiowania samego obiektu.
GoldBishop
30

Radziłbym NIE używać global/ window/ evaldo tego celu.
Zamiast tego zrób to w ten sposób:

zdefiniuj wszystkie metody jako właściwości Handler:

var Handler={};

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

Teraz nazwij to tak

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

Wyjście: jerry

JerryGoyal
źródło
17

możesz to zrobić w ten sposób:

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

var myObject = new MyClass();
myObject["abc"]();
Szymon
źródło
5

W ciągu ServiceWorkerlub Workerwymienić windowz self:

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

Pracownicy nie mają dostępu do DOM, dlatego windowjest to nieprawidłowe odniesienie. W tym celu równoważny globalny identyfikator zakresu to self.

OXiGEN
źródło
2

Nie polecałbym korzystania z okna, jak sugerują niektóre inne odpowiedzi. Używaj thisi stosuj odpowiednio.

this['yourDynamicFcnName'](arguments);

Kolejną fajną sztuczką jest wywoływanie w różnych zakresach i używanie go do dziedziczenia. Powiedzmy, że funkcja została zagnieżdżona i chcesz uzyskać dostęp do globalnego obiektu okna. Możesz to zrobić:

this['yourDynamicFcnName'].call(window, arguments);
Tim Moses
źródło
1

Cześć, spróbuj tego,

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

sam obsłuży parametry.

mathi
źródło
nieprzechwycony błąd odniesienia - nazwa funkcji nie jest zdefiniowana
brianlmerritt
@brianlmerritt musisz zdefiniować wartość functionName... osoba odpowiadająca założyła, że już ją zdefiniowałeś.
GoldBishop
Wygląda na to, że nowa funkcja () nie może być używana do tego celu.
JCH77
-1

Oto działające i proste rozwiązanie do sprawdzania istnienia funkcji i triaging, które działają dynamicznie przez inną funkcję;

Funkcja wyzwalania

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

i możesz teraz generować funkcję dynamicznie, na przykład używając php w ten sposób

function runThis_func(my_Parameter){

    alert(my_Parameter +" triggerd");
}

teraz możesz wywołać funkcję używając dynamicznie generowanego zdarzenia

<?php

$name_frm_somware ="runThis_func";

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

?>

dokładny kod HTML, którego potrzebujesz, to

<input type="button" value="Button" onclick="runDynmicFunction('runThis_func');">
Aylian Craspa
źródło
-3

Spróbuj z tym:

var fn_name = "Colours",
fn = eval("populate_"+fn_name);
fn(args1,argsN);
Gilberto
źródło
Jakie są konsekwencje stosowania tego wzorca? Czytałem, że evalfunkcja ma dziwne skutki uboczne związane z jej użyciem. Generalnie staram się trzymać od tego z daleka, chyba że jest to ostateczność.
GoldBishop