How do I call a dynamically-named method in Javascript?
Asked Answered
B

13

141

I am working on dynamically creating some JavaScript that will be inserted into a web page as it's being constructed.

The JavaScript will be used to populate a listbox based on the selection in another listbox. When the selection of one listbox is changed it will call a method name based on the selected value of the listbox.

For example:

Listbox1 contains:

  • Colours
  • Shapes

If Colours is selected then it will call a populate_Colours method that populates another listbox.

To clarify my question: How do I make that populate_Colours call in JavaScript?

Belanger answered 9/6, 2009 at 12:18 Comment(2)
I'd recommend against this in favour of having local branches in a single 'populate' method. It would make it more testable and look less "hacky"Backplate
see my answer here. call by name in javascriptRinghals
A
246

Assuming the populate_Colours method is in the global namespace, you may use the following code, which exploits both that all object properties may be accessed as though the object were an associative array, and that all global objects are actually properties of the window host object.

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

// Call function:
window[method_prefix + method_name](arg1, arg2);
Ambros answered 9/6, 2009 at 12:22 Comment(10)
Thanks for the response. The 'window' bit really threw me until I googled it and found that global objects are part of the window object. Now it makes sense! Thank you. FYI I found a good page about it here devlicio.us/blogs/sergio_pereira/archive/2009/02/09/…Belanger
I did something similar except the functions I was targeting were in the jQuery "fn" namespace. For example, $.fn[method_prefix + method_name](arg1, arg2);Cloakroom
Nice. Worth adding a try/catch block, perhaps.Lemuellemuela
This may be obvious to some, but for those that can't get it to work: throw the function outside your $(function () { and window.load code :)Theresa
How to call this type of functions dynamically? alertify.[dynamicFunctionName](var); ??Varuna
Why can't you use ['alert']('Hi') since the window namespace is the default namespace?Skiver
@peter Because square brackets are not property accessors in this context, but denote an Array. Arrays are not functions, so you can’t call them.Coadjutrix
@SizzlingCode You can’t use dot notation and bracket notation at the same time.Coadjutrix
Why nobody raised the issue of polluting the global object? Especially with such generic names. Beware, this approach will bite you seriously as you build the system comprising more than 2-3 external libs.Openhearth
read this post #19417774Warman
H
51

I would recommend NOT to use global / window / eval for this purpose.
Instead, do it this way:

define all methods as properties of Handler:

var Handler={};

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

Now call it like this

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

Output: jerry


Case when importing functions from different files

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

const Handler= {
  func1,
  func2
};

Handler["func1"]("sic mundus");
Handler["func2"]("creatus est");
Himalayas answered 20/1, 2018 at 9:26 Comment(1)
why NOT to use global / window / eval?Nunatak
E
49

As Triptych points out, you can call any global scope function by finding it in the host object's contents.

A cleaner method, which pollutes the global namespace much less, is to explicitly put the functions into an array directly like so:

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

This array could also be a property of some object other than the global host object too meaning that you can effectively create your own namespace as many JS libraries such as jQuery do. This is useful for reducing conflicts if/when you include multiple separate utility libraries in the same page, and (other parts of your design permitting) can make it easier to reuse the code in other pages.

You could also use an object like so, which you might find cleaner:

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

Note that with either an array or an object, you can use either method of setting or accessing the functions, and can of course store other objects in there too. You can further reduce the syntax of either method for content that isn't that dynamic by using JS literal notation like so:

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

Edit: of course for larger blocks of functionality you can expand the above to the very common "module pattern" which is a popular way to encapsulate code features in an organised manner.

Eaglet answered 9/6, 2009 at 12:51 Comment(6)
That's a nice way of keeping it clean. How would I call the method though? Would window[dyn_functions['populate_Colours'](arg1, arg2) work?Belanger
Answering my own question - I've just tested window[dyn_functions['populate_Colours'](arg1,arg2)]; and it does indeed work.Belanger
As epascarello points out, you usually don't need "window" - "dyn_functions['populate_Colours'](arg1,arg2);" will work. In fact not including the global object's name will make code more portable if you are writing routines that might ever be used in a JS environment other than a web browser. There is an exception to this though: if you have a local variable called dyn_functions in a function then you would need to be more specific which you are referring to, but this situation is best avoided (by having sensible naming conventions) anyway.Eaglet
Since this post is from '09 you probably know this by now, but you're creating an array, then assigning to the array's properties (not indexes). You might as well do var dyn_functions = {}; so you don't needlessly create an array... this isn't a huge issue though.Indihar
overly complicated answer but does work. I would think the resource load for scenario where I have series of patterned functions and i need a decision tree to choose the execution, this method might be overly complex to perform the task. Albeit, if I was wiring up my own class object, this would be the preferred approach to defining the object itself.Tempura
This is more generic and better than having global functions in window object.Impropriate
J
20

you can do it like this:

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

var myObject = new MyClass();
myObject["abc"]();
Jahncke answered 20/12, 2015 at 10:13 Comment(0)
Z
6

Within a ServiceWorker or Worker, replace window with self:

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

Workers have no access to the DOM, therefore window is an invalid reference. The equivalent global scope identifier for this purpose is self.

Zippora answered 25/8, 2018 at 21:24 Comment(0)
M
6

I wouldn't recommend using the window as some of the other answers suggest. Use this and scope accordingly.

this['yourDynamicFcnName'](arguments);

Another neat trick is calling within different scopes and using it for inheritance. Let's say you had nested the function and want access to the global window object. You could do this:

this['yourDynamicFcnName'].call(window, arguments);
Matchbox answered 5/1, 2020 at 20:3 Comment(4)
How can I do it typescript? I have a method in class, which will iterate array of object, which has functionName and function argument. To be called functions are present in same class. However I get error as this[functionName](funcArgument) is not a functionVinny
Can you share a codepen example? With classes make sure to think about lexical scope.Matchbox
WIll you add an example for doing this when window does not exist like in Node?Angelineangelique
The window doesn't have to exist, I just gave that as an example. You can use any object, and from my memory I think node does have a global this scoped to their own object, so the first option should work perfectly in node or the browser.Matchbox
C
4

Just do it

class User

  getName() 
  {   

    return "dilo";
   }

}

let user =new User();
let dynamicMethod='getName';
console.log(user[dynamicMethod]()); //dilo

 
Carriecarrier answered 12/5, 2021 at 18:1 Comment(1)
Thank you for this! Simple fundamental answer, works in all types of js, maybe missing { following class User ?Angelineangelique
N
1

Hi try this,

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

it will handle the parameters itself.

Nonsmoker answered 29/4, 2013 at 9:59 Comment(4)
uncaught reference error - functionName is not definedHoney
@Honey you have to define the value for functionName...the answerer made the assumption that you already had that defined.Tempura
It seems new Function() cannot be used like that for this purpose.Glower
doesnt work for me g = function(){return 'l'}; var callback_function = new Function(g);Manic
G
0

A simple function to call a function dynamically with parameters:

this.callFunction = this.call_function = function(name) {
    var args = Array.prototype.slice.call(arguments, 1);
    return window[name].call(this, ...args);
};

function sayHello(name, age) {
    console.log('hello ' + name + ', your\'e age is ' + age);
    return some;
}

console.log(call_function('sayHello', 'john', 30)); // hello john, your'e age is 30

Gunsmith answered 20/10, 2020 at 2:27 Comment(0)
D
0

Try These

Call Functions With Dynamic Names, like this:

let dynamic_func_name = 'alert';
(new Function(dynamic_func_name+'()'))()

with parameters:

let dynamic_func_name = 'alert';
let para_1 = 'HAHAHA';
let para_2 = 'ABCD';
(new Function(`${dynamic_func_name}('${para_1}','${para_2}')`))()

Run Dynamic Code:

let some_code = "alert('hahaha');";
(new Function(some_code))()
Donovan answered 12/1, 2021 at 13:47 Comment(0)
L
0

// FUNCTIONS
const funcs = {

  func1() {
    console.log('func1 accessed');
  },

  func2() {
    console.log('func2 accessed');
  }

}

// DYNAMIC FUNCTION NAME
const nameFunc = 'func2';

// DYNAMIC ACCESS TO FUNCTIONS
funcs[nameFunc]();
Longwinded answered 21/6, 2023 at 20:57 Comment(0)
V
-2

Here is a working and simple solution for checking existence of a function and triaging that function dynamically by another function;

Trigger function

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

and you can now generate the function dynamically maybe using php like this

function runThis_func(my_Parameter){

    alert(my_Parameter +" triggerd");
}

now you can call the function using dynamically generated event

<?php

$name_frm_somware ="runThis_func";

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

?>

the exact HTML code you need is

<input type="button" value="Button" onclick="runDynmicFunction('runThis_func');">
Ventilator answered 23/3, 2018 at 8:21 Comment(0)
H
-4

Try with this:

var fn_name = "Colours",
fn = eval("populate_"+fn_name);
fn(args1,argsN);
Halpin answered 11/8, 2017 at 16:47 Comment(2)
What are the implications of using this pattern? I have read that the eval function has some wierd side-effects related to its use. I generally try to stay away from it, unless it is a last resort.Tempura
Eval'ing dynamic content makes it very easy for a hacker to inject and execute their own code into yoursAtman

© 2022 - 2024 — McMap. All rights reserved.