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.