Come posso chiamare un metodo con nome dinamico in Javascript?


113

Sto lavorando alla creazione dinamica di JavaScript che verrà inserito in una pagina web mentre viene costruita.

Il JavaScript verrà utilizzato per popolare un in listboxbase alla selezione in un altro listbox. Quando la selezione di uno listboxviene modificata, chiamerà un nome di metodo basato sul valore selezionato di listbox.

Per esempio:

Listbox1 contiene:

  • Colours
  • Shapes

Se Coloursè selezionato, chiamerà un populate_Coloursmetodo che ne popola un altro listbox.

Per chiarire la mia domanda: come si effettua la populate_Colourschiamata in JavaScript?


Lo sconsiglio a favore di avere filiali locali in un unico metodo di "popolamento". Lo renderebbe più testabile e sembrerebbe meno "hacky"
Aaron Powell

vedi la mia risposta qui. chiama per nome in javascript
Hugo R

Risposte:


208

Supponendo che il populate_Coloursmetodo si trovi nello spazio dei nomi globale, è possibile utilizzare il codice seguente, che sfrutta sia il fatto che è possibile accedere a tutte le proprietà dell'oggetto come se l'oggetto fosse un array associativo, sia che tutti gli oggetti globali sono effettivamente proprietà windowdell'oggetto host.

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

// Call function:
window[method_prefix + method_name](arg1, arg2);

9
Grazie per la risposta. Il bit "window" mi ha davvero spiazzato finché non l'ho cercato su Google e ho scoperto che gli oggetti globali fanno parte dell'oggetto finestra. Ora ha senso! Grazie. Cordiali saluti, ho trovato una buona pagina a riguardo qui devlicio.us/blogs/sergio_pereira/archive/2009/02/09/…
Chris B

3
Ho fatto qualcosa di simile tranne che le funzioni che stavo prendendo di mira erano nello spazio dei nomi jQuery "fn". Ad esempio,$.fn[method_prefix + method_name](arg1, arg2);
codecraig

1
Bello. Vale la pena aggiungere un blocco try/ catch, forse.
LeeGee

Questo può essere ovvio per alcuni, ma per quelli che non riescono a farlo funzionare: lancia la funzione fuori dal tuo codice $(function () {e window.load:)
Stan Smulders

1
@peter Perché le parentesi quadre non sono funzioni di accesso di proprietà in questo contesto, ma indicano un Array. Gli array non sono funzioni, quindi non puoi chiamarli.
user4642212

39

Come sottolinea Triptych, è possibile chiamare qualsiasi funzione di ambito globale trovandola nel contenuto dell'oggetto host.

Un metodo più pulito, che inquina molto meno lo spazio dei nomi globale, consiste nell'inserire esplicitamente le funzioni in un array direttamente in questo modo:

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

Questo array potrebbe anche essere una proprietà di qualche oggetto diverso dall'oggetto host globale, il che significa che puoi creare efficacemente il tuo spazio dei nomi come fanno molte librerie JS come jQuery. Ciò è utile per ridurre i conflitti se / quando si includono più librerie di utilità separate nella stessa pagina e (altre parti del progetto lo consentono) può semplificare il riutilizzo del codice in altre pagine.

Potresti anche usare un oggetto come questo, che potresti trovare più pulito:

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

Si noti che con un array o un oggetto, è possibile utilizzare entrambi i metodi di impostazione o di accesso alle funzioni e, ovviamente, memorizzare anche altri oggetti. Puoi ridurre ulteriormente la sintassi di entrambi i metodi per i contenuti che non sono così dinamici utilizzando la notazione letterale JS in questo modo:

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

Modifica: ovviamente per blocchi di funzionalità più grandi è possibile espandere quanto sopra al "modello di modulo" molto comune, che è un modo popolare per incapsulare le funzionalità del codice in modo organizzato.


È un bel modo per mantenerlo pulito. Come chiamerei il metodo però? Window [dyn_functions ['populate_Colours'] (arg1, arg2) funzionerebbe?
Chris B,

Rispondendo alla mia domanda - ho appena testato window [dyn_functions ['populate_Colours'] (arg1, arg2)]; e funziona davvero.
Chris B,

4
Come sottolinea epascarello, di solito non hai bisogno di "window" - "dyn_functions ['populate_Colours'] (arg1, arg2);" funzionerà. In effetti, non includere il nome dell'oggetto globale renderà il codice più portabile se si scrivono routine che potrebbero essere utilizzate in un ambiente JS diverso da un browser web. C'è un'eccezione a questo però: se hai una variabile locale chiamata dyn_functions in una funzione, allora dovresti essere più specifico a cui ti riferisci, ma questa situazione è meglio evitare (avendo convenzioni di denominazione ragionevoli) comunque.
David Spillett,

1
Poiché questo post è del '09, probabilmente lo sai ormai, ma stai creando un array, quindi assegnando alle proprietà dell'array (non agli indici). Potresti anche farlo in var dyn_functions = {};modo da non creare inutilmente un array ... questo non è un grosso problema però.
David Sherret,

risposta eccessivamente complicata ma funziona. Penserei che il carico di risorse per lo scenario in cui ho una serie di funzioni modellate e ho bisogno di un albero decisionale per scegliere l'esecuzione, questo metodo potrebbe essere eccessivamente complesso per eseguire l'attività. Anche se, se stessi cablando il mio oggetto di classe, questo sarebbe l'approccio preferito per definire l'oggetto stesso.
GoldBishop

30

Consiglierei di NON usare global/ window/ evalper questo scopo.
Invece, fallo in questo modo:

definire tutti i metodi come proprietà di Handler:

var Handler={};

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

Ora chiamalo così

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

Uscita: jerry


17

puoi farlo in questo modo:

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

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

5

All'interno di un ServiceWorkero Worker, sostituire windowcon self:

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

I lavoratori non hanno accesso al DOM, quindi windowè un riferimento non valido. L'identificatore di ambito globale equivalente per questo scopo è self.


2

Non consiglierei di usare la finestra come suggeriscono alcune delle altre risposte. Usa thise ambito di conseguenza.

this['yourDynamicFcnName'](arguments);

Un altro trucco accurato è chiamare in diversi ambiti e usarlo per l'ereditarietà. Supponiamo che tu abbia annidato la funzione e desideri accedere all'oggetto finestra globale. Potresti farlo:

this['yourDynamicFcnName'].call(window, arguments);

1

Ciao prova questo

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

gestirà i parametri stessi.


errore di riferimento non
rilevato

@brianlmerritt devi definire il valore per functionName... chi ha risposto ha supposto che lo avessi già definito.
GoldBishop

Sembra che new Function () non possa essere utilizzato in questo modo per questo scopo.
JCH77

-1

Ecco una soluzione semplice e funzionante per verificare l' esistenza di una funzione e triage di quella funzione dinamicamente da un'altra funzione;

Funzione trigger

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

e ora puoi generare la funzione dinamicamente magari usando php come questo

function runThis_func(my_Parameter){

    alert(my_Parameter +" triggerd");
}

ora puoi chiamare la funzione usando un evento generato dinamicamente

<?php

$name_frm_somware ="runThis_func";

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

?>

il codice HTML esatto di cui hai bisogno è

<input type="button" value="Button" onclick="runDynmicFunction('runThis_func');">

-3

Prova con questo:

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

Quali sono le implicazioni dell'utilizzo di questo modello? Ho letto che la evalfunzione ha alcuni strani effetti collaterali legati al suo utilizzo. In genere cerco di starne lontano, a meno che non sia l'ultima risorsa.
GoldBishop
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.