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?


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

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.


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


17

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

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

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

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.


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

1

Cześć, spróbuj tego,

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

sam obsłuży parametry.


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

-3

Spróbuj z tym:

var fn_name = "Colours",
fn = eval("populate_"+fn_name);
fn(args1,argsN);

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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.