[javascript] Dynamic function name in javascript?

I have this:

this.f = function instance(){};

I would like to have this:

this.f = function ["instance:" + a](){};

This question is related to javascript function

The answer is


I struggled a lot with this issue. @Albin solution worked like a charm while developing, but it did not work when I changed it to production. After some debugging I realized how to achieve what I needed. I'm using ES6 with CRA (create-react-app), which means it's bundled by Webpack.

Lets say you have a file that exports the functions you need:

myFunctions.js

export function setItem(params) {
  // ...
}

export function setUser(params) {
  // ...
}

export function setPost(params) {
  // ...
}

export function setReply(params) {
  // ...
}

And you need to dynamically call these functions elsewhere:

myApiCalls.js

import * as myFunctions from 'path_to/myFunctions';
/* note that myFunctions is imported as an array,
 * which means its elements can be easily accessed
 * using an index. You can console.log(myFunctions).
 */

function accessMyFunctions(res) {
  // lets say it receives an API response
  if (res.status === 200 && res.data) {
    const { data } = res;
    // I want to read all properties in data object and 
    // call a function based on properties names.
    for (const key in data) {
      if (data.hasOwnProperty(key)) {
        // you can skip some properties that are usually embedded in
        // a normal response
        if (key !== 'success' && key !== 'msg') {
          // I'm using a function to capitalize the key, which is
          // used to dynamically create the function's name I need.
          // Note that it does not create the function, it's just a
          // way to access the desired index on myFunctions array.
          const name = `set${capitalizeFirstLetter(key)}`;
          // surround it with try/catch, otherwise all unexpected properties in
          // data object will break your code.
          try {
            // finally, use it.
            myFunctions[name](data[key]);
          } catch (error) {
            console.log(name, 'does not exist');
            console.log(error);
          }
        }
      }
    }
  }
}


What about

this.f = window["instance:" + a] = function(){};

The only drawback is that the function in its toSource method wouldn't indicate a name. That's usually only a problem for debuggers.


the best way it is create object with list of dynamic functions like:

const USER = 'user';

const userModule = {
  [USER + 'Action'] : function () { ... }, 
  [USER + 'OnClickHandler'] : function () { ... }, 
  [USER + 'OnCreateHook'] : function () { ... }, 
}

Thank you Marcosc! Building on his answer, if you want to rename any function, use this:

// returns the function named with the passed name
function namedFunction(name, fn) {
    return new Function('fn',
        "return function " + name + "(){ return fn.apply(this,arguments)}"
    )(fn)
}

If you want to have a dynamic function like the __call function in PHP, you could use Proxies.

const target = {};

const handler = {
  get: function (target, name) {
    return (myArg) => {
      return new Promise(resolve => setTimeout(() => resolve('some' + myArg), 600))
    }
  }
};

const proxy = new Proxy(target, handler);

(async function() {
  const result = await proxy.foo('string')
  console.log('result', result) // 'result somestring' after 600 ms
})()

function myFunction() {
    console.log('It works!');
}

var name = 'myFunction';

window[name].call();

I might be missing the obvious here, but what's wrong with just adding the name? functions are invoked regardless of their name. names are just used for scoping reasons. if you assign it to a variable, and it's in scope, it can be called. hat happens is your are executing a variable which happens to be a function. if you must have a name for identification reasons when debugging, insert it between the keyword function and the opening brace.

_x000D_
_x000D_
var namedFunction = function namedFunction (a,b) {return a+b};_x000D_
_x000D_
alert(namedFunction(1,2));_x000D_
alert(namedFunction.name);_x000D_
alert(namedFunction.toString());
_x000D_
_x000D_
_x000D_

an alternative approach is to wrap the function in an outer renamed shim, which you can also pass into an outer wrapper, if you don't want to dirty the surrounding namespace. if you are wanting to actually dynamically create the function from strings (which most of these examples do), it's trivial to rename the source to do what you want. if however you want to rename existing functions without affecting their functionality when called elsewhere, a shim is the only way to achieve it.

_x000D_
_x000D_
(function(renamedFunction) {_x000D_
_x000D_
  alert(renamedFunction(1,2));_x000D_
  alert(renamedFunction.name);_x000D_
  alert(renamedFunction.toString());_x000D_
  alert(renamedFunction.apply(this,[1,2]));_x000D_
_x000D_
_x000D_
})(function renamedFunction(){return namedFunction.apply(this,arguments);});_x000D_
_x000D_
function namedFunction(a,b){return a+b};
_x000D_
_x000D_
_x000D_


I think most suggestions here are suboptimal, by using eval, hacky solutions or wrappers. As of ES2015 names are inferred from the syntactic position for variables and properties.

So this will work just fine:

const name = 'myFn';
const fn = {[name]: function() {}}[name];
fn.name // 'myFn'

Resist the temptation to create named function factory methods as you wouldn't be able to pass the function from outside and retrofit it into the syntactic position to infer its name. Then it's already too late. If you really need that, you have to create a wrapper. Someone did that here, but that solution doesn't work for classes (which are also functions).

A much more in-depth answer with all the variants outlined has been written here: https://stackoverflow.com/a/9479081/633921


For setting the name of an existing anonymous function:
(Based on @Marcosc's answer)

var anonymous = function() { return true; }

var name = 'someName';
var strFn = anonymous.toString().replace('function ', 'return function ' + name);
var fn = new Function(strFn)();

console.log(fn()); // —> true

Demo.

Note: Don't do it ;/


This is BEST solution, better then new Function('return function name(){}')().

Eval is fastest solution:

enter image description here

var name = 'FuncName'
var func = eval("(function " + name + "(){})")

This utility function merge multiple functions into one (using a custom name), only requirement is that provided functions are properly "new lined" at start and end of its scoop.

const createFn = function(name, functions, strict=false) {

    var cr = `\n`, a = [ 'return function ' + name + '(p) {' ];

    for(var i=0, j=functions.length; i<j; i++) {
        var str = functions[i].toString();
        var s = str.indexOf(cr) + 1;
        a.push(str.substr(s, str.lastIndexOf(cr) - s));
    }
    if(strict == true) {
        a.unshift('\"use strict\";' + cr)
    }
    return new Function(a.join(cr) + cr + '}')();
}

// test
var a = function(p) {
    console.log("this is from a");
}
var b = function(p) {
    console.log("this is from b");
}
var c = function(p) {
    console.log("p == " + p);
}

var abc = createFn('aGreatName', [a,b,c])

console.log(abc) // output: function aGreatName()

abc(123)

// output
this is from a
this is from b
p == 123

The syntax function[i](){} implies an object with property values that are functions, function[], indexed by the name, [i].
Thus
{"f:1":function(){}, "f:2":function(){}, "f:A":function(){}, ... } ["f:"+i].

{"f:1":function f1(){}, "f:2":function f2(){}, "f:A":function fA(){}} ["f:"+i] will preserve function name identification. See notes below regarding :.

So,

javascript: alert(
  new function(a){
    this.f={"instance:1":function(){}, "instance:A":function(){}} ["instance:"+a]
  }("A") . toSource()
);

displays ({f:(function () {})}) in FireFox.
(This is almost the same idea as this solution, only it uses a generic object and no longer directly populates the window object with the functions.)

This method explicitly populates the environment with instance:x.

javascript: alert(
  new function(a){
    this.f=eval("instance:"+a+"="+function(){})
  }("A") . toSource()
);
alert(eval("instance:A"));

displays

({f:(function () {})})

and

function () {
}

Though the property function f references an anonymous function and not instance:x, this method avoids several problems with this solution.

javascript: alert(
  new function(a){
    eval("this.f=function instance"+a+"(){}")
  }("A") . toSource()
);
alert(instanceA);    /* is undefined outside the object context */

displays only

({f:(function instanceA() {})})
  • The embedded : makes the javascript function instance:a(){} invalid.
  • Instead of a reference, the function's actual text definition is parsed and interpreted by eval.

The following is not necessarily problematic,

  • The instanceA function is not directly available for use as instanceA()

and so is much more consistent with the original problem context.

Given these considerations,

this.f = {"instance:1": function instance1(){},
          "instance:2": function instance2(){},
          "instance:A": function instanceA(){},
          "instance:Z": function instanceZ(){}
         } [ "instance:" + a ]

maintains the global computing environment with the semantics and syntax of the OP example as much as possible.


In recent engines, you can do

_x000D_
_x000D_
function nameFunction(name, body) {_x000D_
  return {[name](...args) {return body(...args)}}[name]_x000D_
}_x000D_
_x000D_
_x000D_
_x000D_
const x = nameFunction("wonderful function", (p) => p*2)_x000D_
console.log(x(9)) // => 18_x000D_
console.log(x.name) // => "wonderful function"
_x000D_
_x000D_
_x000D_


Dynamic methods of an object may be created using Object Literal Extensions provided by ECMAScript 2015 (ES6):

const postfixes = ['foo', 'bar'];

const mainObj = {};

const makeDynamic = (postfix) => {
  const newMethodName = 'instance: ' + postfix;
  const tempObj = {
    [newMethodName]() {
      console.log(`called method ${newMethodName}`);
    }
  }
  Object.assign(mainObj, tempObj);
  return mainObj[newMethodName]();
}

const processPostfixes = (postfixes) => { 
  for (const postfix of postfixes) {
    makeDynamic(postfix); 
  }
};

processPostfixes(postfixes);

console.log(mainObj);

The output of running the code above is:

"called method instance: foo"
"called method instance: bar"
Object {
  "instance: bar": [Function anonymous],
  "instance: foo": [Function anonymous]
}

You can use Object.defineProperty as noted in the MDN JavaScript Reference:

var myName = "myName";
var f = function () { return true; };
Object.defineProperty(f, 'name', {value: myName, writable: false});

This will basically do it at the most simple level:

"use strict";
var name = "foo";
var func = new Function(
     "return function " + name + "(){ alert('sweet!')}"
)();

//call it, to test it
func();

If you want to get more fancy, I have a written an article on "Dynamic function names in JavaScript".


I had better luck in combining Darren's answer and kyernetikos's answer.

_x000D_
_x000D_
const nameFunction = function (fn, name) {_x000D_
  return Object.defineProperty(fn, 'name', {value: name, configurable: true});_x000D_
};_x000D_
_x000D_
/* __________________________________________________________________________ */_x000D_
_x000D_
let myFunc = function oldName () {};_x000D_
_x000D_
console.log(myFunc.name); // oldName_x000D_
_x000D_
myFunc = nameFunction(myFunc, 'newName');_x000D_
_x000D_
console.log(myFunc.name); // newName
_x000D_
_x000D_
_x000D_

Note: configurable is set to true to match the standard ES2015 spec for Function.name1

This especially helped in getting around an error in Webpack similar to this one.

Update: I was thinking of publishing this as an npm package, but this package from sindresorhus does exactly the same thing.

  1. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name

The most voted answer has got already defined [String] function body. I was looking for the solution to rename already declared function's name and finally after an hour of struggling I've dealt with it. It:

  • takes the alredy declared function
  • parses it to [String] with .toString() method
  • then overwrites the name (of named function) or appends the new one (when anonymous) between function and (
  • then creates the new renamed function with new Function() constructor

_x000D_
_x000D_
function nameAppender(name,fun){_x000D_
  const reg = /^(function)(?:\s*|\s+([A-Za-z0-9_$]+)\s*)(\()/;_x000D_
  return (new Function(`return ${fun.toString().replace(reg,`$1 ${name}$3`)}`))();_x000D_
}_x000D_
_x000D_
//WORK FOR ALREADY NAMED FUNCTIONS:_x000D_
function hello(name){_x000D_
  console.log('hello ' + name);_x000D_
}_x000D_
_x000D_
//rename the 'hello' function_x000D_
var greeting = nameAppender('Greeting', hello); _x000D_
_x000D_
console.log(greeting); //function Greeting(name){...}_x000D_
_x000D_
_x000D_
//WORK FOR ANONYMOUS FUNCTIONS:_x000D_
//give the name for the anonymous function_x000D_
var count = nameAppender('Count',function(x,y){ _x000D_
  this.x = x;_x000D_
  this.y = y;_x000D_
  this.area = x*y;_x000D_
}); _x000D_
_x000D_
console.log(count); //function Count(x,y){...}
_x000D_
_x000D_
_x000D_


You can use Dynamic Function Name and parameters like this.

1) Define function Separate and call it

let functionName = "testFunction";
let param = {"param1":1 , "param2":2};

var func = new Function(
   "return " + functionName 
)();

func(param);

function testFunction(params){
   alert(params.param1);
}

2) Define function code dynamic

let functionName = "testFunction(params)";
let param = {"param1":"1" , "param2":"2"};
let functionBody = "{ alert(params.param1)}";

var func = new Function(
    "return function " + functionName + functionBody 
)();

func(param);

There are two methods to achieve this, and they have their pros and cons.


name property definition

Defining immutable name property of a function.

Pros

  • Every character is available for the name. (eg. () ? {}/1/??/ :D #GO(@*#%! /*)

Cons

  • The function's syntactic (“expressional”) name may not correspond with its name property value.

Function expression evaluation

Making a named function expression and evaluating it with Function constructor.

Pros

  • The function's syntactic (“expressional”) name always corresponds with its name property value.

Cons

  • Whitespaces (and etc.) are not available for the name.
  • Expression-injectable (eg. For input (){}/1//, the expression is return function (){}/1//() {}, gives NaN instead of a function.).

const demoeval = expr => (new Function(`return ${expr}`))();

// `name` property definition
const method1 = func_name => {
    const anon_func = function() {};
    Object.defineProperty(anon_func, "name", {value: func_name, writable: false});
    return anon_func;
};

const test11 = method1("DEF_PROP"); // No whitespace
console.log("DEF_PROP?", test11.name); // "DEF_PROP"
console.log("DEF_PROP?", demoeval(test11.toString()).name); // ""

const test12 = method1("DEF PROP"); // Whitespace
console.log("DEF PROP?", test12.name); // "DEF PROP"
console.log("DEF PROP?", demoeval(test12.toString()).name); // ""

// Function expression evaluation
const method2 = func_name => demoeval(`function ${func_name}() {}`);

const test21 = method2("EVAL_EXPR"); // No whitespace
console.log("EVAL_EXPR?", test21.name); // "EVAL_EXPR"
console.log("EVAL_EXPR?", demoeval(test21.toString()).name); // "EVAL_EXPR"

const test22 = method2("EVAL EXPR"); // Uncaught SyntaxError: Unexpected identifier

You was near:

_x000D_
_x000D_
this["instance_" + a] = function () {...};
_x000D_
_x000D_
_x000D_

{...};