¿Cómo llamo a un método con nombre dinámico en Javascript?

113

Estoy trabajando en la creación dinámica de JavaScript que se insertará en una página web a medida que se construye.

El JavaScript se utilizará para rellenar un listboxbasado en la selección de otro listbox. Cuando listboxse cambia la selección de uno , llamará a un nombre de método basado en el valor seleccionado de listbox.

Por ejemplo:

Listbox1 contiene:

  • Colours
  • Shapes

Si Coloursestá seleccionado, llamará a un populate_Coloursmétodo que rellene otro listbox.

Para aclarar mi pregunta: ¿Cómo hago esa populate_Coloursllamada en JavaScript?

Chris B
fuente
No recomendaría esto a favor de tener sucursales locales en un único método de 'poblar'. Lo haría más comprobable y parecería menos "hacky"
Aaron Powell
mira mi respuesta aquí. llamar por nombre en javascript
Hugo R

Respuestas:

208

Suponiendo que el populate_Coloursmétodo está en el espacio de nombres global, puede usar el siguiente código, que explota tanto que se puede acceder a todas las propiedades del objeto como si el objeto fuera una matriz asociativa, y que todos los objetos globales son en realidad propiedades del windowobjeto anfitrión.

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

// Call function:
window[method_prefix + method_name](arg1, arg2);
Tríptico
fuente
9
Gracias por la respuesta. El bit de 'ventana' realmente me desconcertó hasta que lo busqué en Google y descubrí que los objetos globales son parte del objeto de la ventana. ¡Ahora tiene sentido! Gracias. Para su información, encontré una buena página al respecto aquí devlicio.us/blogs/sergio_pereira/archive/2009/02/09/…
Chris B
3
Hice algo similar, excepto que las funciones a las que me dirigía estaban en el espacio de nombres jQuery "fn". Por ejemplo,$.fn[method_prefix + method_name](arg1, arg2);
codecraig
1
Agradable. Quizás valga la pena agregar un bloque try/ catch.
LeeGee
Esto puede ser obvio para algunos, pero para aquellos que no pueden hacer que funcione: arroje la función fuera de su código $(function () {y window.load:)
Stan Smulders
1
@peter Porque los corchetes no son descriptores de acceso de propiedad en este contexto, pero denotan un Array. Las matrices no son funciones, por lo que no puede llamarlas.
user4642212
39

Como señala Triptych, puede llamar a cualquier función de alcance global encontrándola en el contenido del objeto host.

Un método más limpio, que contamina mucho menos el espacio de nombres global, es poner explícitamente las funciones en una matriz directamente así:

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

Esta matriz también podría ser una propiedad de algún objeto que no sea el objeto de host global, lo que significa que puede crear efectivamente su propio espacio de nombres como lo hacen muchas bibliotecas JS como jQuery. Esto es útil para reducir conflictos si / cuando incluye varias bibliotecas de utilidades separadas en la misma página, y (si otras partes de su diseño lo permiten) puede facilitar la reutilización del código en otras páginas.

También puede usar un objeto como este, que puede encontrar más limpio:

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

Tenga en cuenta que con una matriz o un objeto, puede utilizar cualquier método de configuración o acceso a las funciones y, por supuesto, también puede almacenar otros objetos allí. Puede reducir aún más la sintaxis de cualquiera de los métodos para el contenido que no es tan dinámico mediante el uso de la notación literal JS así:

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

Editar: por supuesto, para bloques de funcionalidad más grandes, puede expandir lo anterior al "patrón de módulo" muy común, que es una forma popular de encapsular características de código de manera organizada.

David Spillett
fuente
Esa es una buena forma de mantenerlo limpio. Sin embargo, ¿cómo llamaría al método? ¿Funcionaría la ventana [dyn_functions ['populate_Colours'] (arg1, arg2)?
Chris B
Respondiendo a mi propia pregunta - Acabo de probar la ventana [dyn_functions ['populate_Colours'] (arg1, arg2)]; y de hecho funciona.
Chris B
4
Como señala epascarello, normalmente no necesita "ventana" - "dyn_functions ['populate_Colours'] (arg1, arg2);" trabajará. De hecho, no incluir el nombre del objeto global hará que el código sea más portátil si está escribiendo rutinas que podrían usarse en un entorno JS que no sea un navegador web. Sin embargo, hay una excepción a esto: si tiene una variable local llamada dyn_functions en una función, entonces necesitaría ser más específico a lo que se refiere, pero es mejor evitar esta situación (teniendo convenciones de nombres sensibles) de todos modos.
David Spillett
1
Dado que esta publicación es del '09, probablemente ya sepa esto, pero está creando una matriz y luego asignándola a las propiedades de la matriz (no a los índices). También puede hacerlo var dyn_functions = {};para no crear una matriz innecesariamente ... aunque esto no es un gran problema.
David Sherret
respuesta demasiado complicada pero funciona. Creo que la carga de recursos para el escenario en el que tengo una serie de funciones con patrones y necesito un árbol de decisiones para elegir la ejecución, este método puede ser demasiado complejo para realizar la tarea. Aunque, si estuviera conectando mi propio objeto de clase, este sería el enfoque preferido para definir el objeto en sí.
GoldBishop
30

Recomendaría NO usar global/ window/ evalpara este propósito.
En su lugar, hazlo de esta manera:

define todos los métodos como propiedades de Handler:

var Handler={};

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

Ahora llámalo así

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

Salida: jerry

JerryGoyal
fuente
17

puedes hacerlo así:

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

var myObject = new MyClass();
myObject["abc"]();
Simón
fuente
5

Dentro de ServiceWorkero Worker, reemplace windowcon self:

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

Los trabajadores no tienen acceso al DOM, por windowlo tanto, es una referencia inválida. El identificador de alcance global equivalente para este propósito es self.

OXIGEN
fuente
2

No recomendaría usar la ventana como sugieren algunas de las otras respuestas. Utilice thisy alcance en consecuencia.

this['yourDynamicFcnName'](arguments);

Otro buen truco es llamar dentro de diferentes ámbitos y usarlo como herencia. Digamos que ha anidado la función y desea acceder al objeto de ventana global. Podrías hacer esto:

this['yourDynamicFcnName'].call(window, arguments);
Tim Moisés
fuente
1

Hola prueba esto

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

manejará los parámetros por sí mismo.

Mathi
fuente
error de referencia no
detectado
@brianlmerritt tienes que definir el valor para functionName... el respondedor asumió que ya lo tenías definido.
GoldBishop
Parece que new Function () no se puede usar así para este propósito.
JCH77
-1

Aquí hay una solución funcional y simple para verificar la existencia de una función y clasificar esa función dinámicamente por otra función;

Función de disparo

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

y ahora puede generar la función dinámicamente, tal vez usando php como este

function runThis_func(my_Parameter){

    alert(my_Parameter +" triggerd");
}

ahora puede llamar a la función usando un evento generado dinámicamente

<?php

$name_frm_somware ="runThis_func";

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

?>

el código HTML exacto que necesita es

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

Prueba con esto:

var fn_name = "Colours",
fn = eval("populate_"+fn_name);
fn(args1,argsN);
Gilberto
fuente
¿Cuáles son las implicaciones de usar este patrón? He leído que la evalfunción tiene algunos efectos secundarios extraños relacionados con su uso. Por lo general, trato de mantenerme alejado, a menos que sea un último recurso.
GoldBishop