Como chamo um método nomeado dinamicamente em Javascript?

113

Estou trabalhando na criação dinâmica de algum JavaScript que será inserido em uma página da web enquanto está sendo construída.

O JavaScript será usado para preencher um com listboxbase na seleção de outro listbox. Quando a seleção de um listboxfor alterada, ele chamará um nome de método com base no valor selecionado de listbox.

Por exemplo:

Listbox1 contém:

  • Colours
  • Shapes

Se Coloursfor selecionado, ele chamará um populate_Coloursmétodo que preenche outro listbox.

Para esclarecer minha pergunta: Como faço essa populate_Colourschamada em JavaScript?

Chris B
fonte
Eu não recomendo isso em favor de ter filiais locais em um único método de 'popular'. Isso o tornaria mais testável e pareceria menos "hacky"
Aaron Powell
veja minha resposta aqui. chamada pelo nome em javascript
Hugo R

Respostas:

208

Assumindo que o populate_Coloursmétodo está no namespace global, você pode usar o código a seguir, que explora que todas as propriedades do objeto podem ser acessadas como se o objeto fosse um array associativo e que todos os objetos globais são realmente propriedades do windowobjeto host.

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

// Call function:
window[method_prefix + method_name](arg1, arg2);
Tríptico
fonte
9
Obrigado pela resposta. A parte 'janela' realmente me surpreendeu até que eu pesquisei no Google e descobri que objetos globais são parte do objeto janela. Agora faz sentido! Obrigado. Para sua informação, encontrei uma boa página sobre isso aqui devlicio.us/blogs/sergio_pereira/archive/2009/02/09/…
Chris B
3
Fiz algo semelhante, exceto que as funções que tinha como alvo estavam no namespace jQuery "fn". Por exemplo,$.fn[method_prefix + method_name](arg1, arg2);
codecraig
1
Agradável. Vale a pena adicionar um bloco try/ catch, talvez.
LeeGee de
Isso pode ser óbvio para alguns, mas para aqueles que não conseguem fazer funcionar: jogue a função fora do seu código $(function () {e window.load:)
Stan Smulders
1
@peter Porque colchetes não são acessadores de propriedade neste contexto, mas denotam um Array. Arrays não são funções, então você não pode chamá-los.
user4642212
39

Como Triptych aponta, você pode chamar qualquer função de escopo global localizando-a no conteúdo do objeto host.

Um método mais limpo, que polui o namespace global muito menos, é colocar explicitamente as funções em uma matriz diretamente, assim:

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

Essa matriz também pode ser uma propriedade de algum objeto diferente do objeto host global, o que significa que você pode criar seu próprio namespace com eficácia, como fazem muitas bibliotecas JS, como jQuery. Isso é útil para reduzir conflitos se / quando você incluir várias bibliotecas de utilitários separadas na mesma página e (se outras partes do seu design permitirem) pode tornar mais fácil reutilizar o código em outras páginas.

Você também pode usar um objeto como este, que pode ser mais limpo:

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

Observe que, com um array ou um objeto, você pode usar qualquer um dos métodos de configuração ou acesso às funções e, é claro, também pode armazenar outros objetos. Você pode reduzir ainda mais a sintaxe de qualquer um dos métodos para conteúdo que não seja tão dinâmico usando a notação literal JS como:

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

Editar: é claro que para blocos maiores de funcionalidade, você pode expandir o acima para o "padrão de módulo" muito comum, que é uma maneira popular de encapsular recursos de código de maneira organizada.

David Spillett
fonte
Essa é uma boa maneira de mantê-lo limpo. Porém, como eu chamaria o método? A janela [dyn_functions ['populate_Colours'] (arg1, arg2) funcionaria?
Chris B
Respondendo minha própria pergunta - acabei de testar window [dyn_functions ['populate_Colours'] (arg1, arg2)]; e realmente funciona.
Chris B
4
Como epascarello aponta, você normalmente não precisa de "window" - "dyn_functions ['populate_Colours'] (arg1, arg2);" vai funcionar. Na verdade, não incluir o nome do objeto global tornará o código mais portátil se você estiver escrevendo rotinas que podem ser usadas em um ambiente JS diferente de um navegador da web. Há uma exceção a isso: se você tem uma variável local chamada dyn_functions em uma função, então você precisa ser mais específico ao que está se referindo, mas é melhor evitar esta situação (por ter convenções de nomenclatura razoáveis) de qualquer maneira.
David Spillett
1
Como este post é de 2009, você provavelmente já sabe disso, mas está criando um array e, em seguida, atribuindo às propriedades do array (não aos índices). Você também pode fazer var dyn_functions = {};isso para não criar um array desnecessariamente ... isso não é um grande problema.
David Sherret
resposta excessivamente complicada, mas funciona. Eu acho que a carga de recursos para o cenário em que tenho uma série de funções padronizadas e preciso de uma árvore de decisão para escolher a execução, esse método pode ser excessivamente complexo para realizar a tarefa. Embora, se eu estivesse conectando meu próprio objeto de classe, essa seria a abordagem preferida para definir o próprio objeto.
GoldBishop
30

Eu recomendaria NÃO usar global/ window/ evalpara essa finalidade.
Em vez disso, faça desta forma:

define todos os métodos como propriedades de Handler:

var Handler={};

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

Agora chame assim

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

Produto: Jerry

JerryGoyal
fonte
17

você pode fazer assim:

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

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

Dentro de ServiceWorkerou Worker, substitua windowpor self:

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

Os trabalhadores não têm acesso ao DOM, portanto, windowé uma referência inválida. O identificador de escopo global equivalente para esse propósito é self.

OXiGEN
fonte
2

Eu não recomendaria usar a janela como algumas das outras respostas sugerem. Use thise escopo de acordo.

this['yourDynamicFcnName'](arguments);

Outro truque interessante é chamar em escopos diferentes e usá-lo para herança. Digamos que você tenha aninhado a função e queira acessar o objeto janela global. Você poderia fazer isso:

this['yourDynamicFcnName'].call(window, arguments);
Tim Moses
fonte
1

Oi tente isso,

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

ele tratará dos próprios parâmetros.

matemática
fonte
erro de referência não detectado - functionName não está definido
brianlmerritt
@brianlmerritt você tem que definir o valor para functionName... o respondente presumiu que você já tinha definido isso.
GoldBishop
Parece que new Function () não pode ser usado dessa forma para este propósito.
JCH77
-1

Aqui está uma solução simples e funcional para verificar a existência de uma função e fazer a triagem dessa função dinamicamente por outra função;

Função de gatilho

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 agora você pode gerar a função dinamicamente, talvez usando php como este

function runThis_func(my_Parameter){

    alert(my_Parameter +" triggerd");
}

agora você pode chamar a função usando um evento gerado dinamicamente

<?php

$name_frm_somware ="runThis_func";

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

?>

o código HTML exato que você precisa é

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

Experimente com isto:

var fn_name = "Colours",
fn = eval("populate_"+fn_name);
fn(args1,argsN);
Gilberto
fonte
Quais são as implicações de usar esse padrão? Eu li que a evalfunção tem alguns efeitos colaterais estranhos relacionados ao seu uso. Eu geralmente tento ficar longe dela, a menos que seja um último recurso.
GoldBishop