Как вызвать метод с динамическим именем в Javascript?


113

Я работаю над динамическим созданием некоторого кода JavaScript, который будет вставлен в веб-страницу по мере ее создания.

JavaScript будет использоваться для заполнения на listboxоснове выбора в другом listbox. Когда выбор одного из них listboxизменен, он будет вызывать имя метода на основе выбранного значения listbox.

Например:

Listbox1 содержит:

  • Colours
  • Shapes

Если Coloursон выбран, он вызовет populate_Coloursметод, который заполняет другой listbox.

Чтобы прояснить мой вопрос: как мне сделать этот populate_Coloursвызов в JavaScript?


Я бы не рекомендовал этого в пользу наличия локальных веток в одном методе «заполнения». Это сделало бы его более тестируемым и менее «хакерским»,
Аарон Пауэлл

см. мой ответ здесь. вызов по имени в javascript
Hugo R

Ответы:


208

Предполагая, что populate_Coloursметод находится в глобальном пространстве имен, вы можете использовать следующий код, который использует как возможность доступа ко всем свойствам объекта, как если бы объект был ассоциативным массивом, так и то, что все глобальные объекты на самом деле являются свойствами windowосновного объекта.

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

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

9
Спасибо за ответ. Бит 'window' действительно бросал меня, пока я не погуглил и не обнаружил, что глобальные объекты являются частью объекта окна. Теперь это имеет смысл! Спасибо. К вашему сведению, я нашел хорошую страницу об этом здесь devlicio.us/blogs/sergio_pereira/archive/2009/02/09/…
Крис Би

3
Я сделал нечто подобное, за исключением того, что функции, на которые я нацелился, находились в пространстве имен jQuery "fn". Например,$.fn[method_prefix + method_name](arg1, arg2);
codecraig 02

1
Ницца. Возможно, стоит добавить try/ catchblock.
LeeGee

Для некоторых это может быть очевидно, но для тех, кто не может заставить это работать: выбросьте функцию за пределы вашего кода $(function () {и window.loadкода :)
Стэн Смолдерс

1
@peter Поскольку квадратные скобки не являются средствами доступа к свойствам в этом контексте, а обозначают массив. Массивы не являются функциями, поэтому их нельзя вызывать.
user4642212

39

Как указывает Триптих, вы можете вызвать любую функцию глобальной области видимости, найдя ее в содержимом хост-объекта.

Более чистый метод, который намного меньше загрязняет глобальное пространство имен, состоит в том, чтобы явно поместить функции в массив прямо следующим образом:

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

Этот массив также может быть свойством какого-либо объекта, кроме глобального объекта хоста, что означает, что вы можете эффективно создавать свое собственное пространство имен, как это делают многие библиотеки JS, такие как jQuery. Это полезно для уменьшения конфликтов, если / когда вы включаете несколько отдельных служебных библиотек на одну страницу, и (если это позволяют другие части вашего дизайна) может упростить повторное использование кода на других страницах.

Вы также можете использовать такой объект, который может оказаться чище:

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

Обратите внимание, что с массивом или объектом вы можете использовать любой метод установки или доступа к функциям, и, конечно, можете хранить там и другие объекты. Вы можете дополнительно сократить синтаксис любого метода для контента, который не является таким динамичным, используя буквальную нотацию JS, например:

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

Изменить: конечно, для более крупных функциональных блоков вы можете расширить приведенное выше до очень распространенного «модульного шаблона», который является популярным способом инкапсуляции функций кода в организованном порядке.


Это хороший способ содержать его в чистоте. Как бы я назвал этот метод? Будет ли работать window [dyn_functions ['populate_Colours'] (arg1, arg2)?
Chris B,

Отвечая на свой вопрос - я только что протестировал window [dyn_functions ['populate_Colours'] (arg1, arg2)]; и это действительно работает.
Chris B,

4
Как указывает эпаскарелло, вам обычно не нужно "window" - "dyn_functions ['populate_Colours'] (arg1, arg2);" буду работать. Фактически, отсутствие имени глобального объекта сделает код более переносимым, если вы пишете процедуры, которые могут когда-либо использоваться в среде JS, отличной от веб-браузера. Однако есть исключение: если у вас есть локальная переменная с именем dyn_functions в функции, тогда вам нужно будет более конкретно указать, о чем вы говорите, но в любом случае этой ситуации лучше избегать (имея разумные соглашения об именах).
Дэвид Спиллетт,

1
Поскольку этот пост от '09, вы, вероятно, уже знаете это, но вы создаете массив, а затем назначаете его свойствам (а не индексам). С тем же успехом вы можете сделать var dyn_functions = {};так, чтобы без необходимости создавать массив ... это не большая проблема.
Дэвид Шеррет

слишком сложный ответ, но работает. Я думаю, что загрузка ресурсов для сценария, в котором у меня есть ряд шаблонных функций, и мне нужно дерево решений для выбора выполнения, этот метод может быть слишком сложным для выполнения задачи. Хотя, если бы я подключал свой собственный объект класса, это был бы предпочтительный подход к определению самого объекта.
GoldBishop

30

Я бы рекомендовал НЕ использовать global/ window/ evalдля этой цели.
Вместо этого сделайте это так:

определить все методы как свойства Handler:

var Handler={};

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

Теперь назовите это так

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

Выход: Джерри


Кейс при импорте функций из разных файлов

import { func1, func2 } from "../utility";

const Handler= {
  func1,
  func2
};

Handler["func1"]("sic mundus");
Handler["func2"]("creatus est");

17

сделать это можно так:

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

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

5

Внутри ServiceWorkerили Workerзамените windowна self:

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

У рабочих нет доступа к DOM, поэтому windowссылка недействительна. Эквивалентный идентификатор глобальной области видимости для этой цели - self.


2

Я бы не рекомендовал использовать окно, как предлагают некоторые другие ответы. Используйте thisи объем соответственно.

this['yourDynamicFcnName'](arguments);

Еще один изящный трюк - вызов в разных областях видимости и использование его для наследования. Допустим, вы вложили функцию и хотите получить доступ к глобальному объекту окна. Вы могли сделать это:

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

1

Привет, попробуй,

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

он сам будет обрабатывать параметры.



@brianlmerritt, вы должны определить значение для functionName... отвечающий сделал предположение, что вы уже это определили.
GoldBishop

Кажется, что new Function () нельзя использовать для этой цели.
JCH77

-1

Вот рабочее и простое решение для проверки существования функции и динамической сортировки этой функции. другой функцией;

Функция триггера

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

и теперь вы можете динамически генерировать функцию, возможно, используя php, как это

function runThis_func(my_Parameter){

    alert(my_Parameter +" triggerd");
}

теперь вы можете вызвать функцию, используя динамически сгенерированное событие

<?php

$name_frm_somware ="runThis_func";

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

?>

точный HTML-код, который вам нужен,

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

-3

Попробуйте с этим:

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

Каковы последствия использования этого шаблона? Я читал, что у этой evalфункции есть некоторые странные побочные эффекты, связанные с ее использованием. Я обычно стараюсь держаться от этого подальше, если только это не последнее средство.
GoldBishop
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.