我有一个JavaScript函数的名称作为字符串。如何将其转换为函数指针以便以后调用?

根据情况,我可能还需要将各种参数传递给该方法。

有些的功能可以采用namespace.namespace.function(args[...])的形式。

#1 楼

除非绝对没有其他选择,否则不要使用eval

如上所述,最好使用以下方法:

window["functionName"](arguments);


但是,这不适用于使用命名空间的功能:

window["My.Namespace.functionName"](arguments); // fail


这是您要这样做的方式:

window["My"]["Namespace"]["functionName"](arguments); // succeeds


为了简化操作并提供一定的灵活性,以下是一种便捷功能:

function executeFunctionByName(functionName, context /*, args */) {
  var args = Array.prototype.slice.call(arguments, 2);
  var namespaces = functionName.split(".");
  var func = namespaces.pop();
  for(var i = 0; i < namespaces.length; i++) {
    context = context[namespaces[i]];
  }
  return context[func].apply(context, args);
}


这样称呼:

executeFunctionByName("My.Namespace.functionName", window, arguments);


注意,您可以在任何想要的上下文中传递,因此与上面的操作相同:

executeFunctionByName("Namespace.functionName", My, arguments);


评论


您知道您不需要整个“ func”构造吗?单独使用“ context.apply”就可以了

– annakata
08-12-11在16:36

当然,我知道-但是我编写函数的方式为那些可能不完全理解正在发生的事情的读者提供了一些清晰度。我写了这个函数,意识到人们阅读它可能需要一些帮助。自您询问以来,我将提供另一种选择。

–詹森·邦廷
08-12-11在16:50

从头开始-代码足够清晰,那些知道,知道的人。如果您像我一样,并且知道自己在做什么,那么使用此代码就可以自己进行更改。堆栈溢出用于教育他人,我认为我的代码对于新手来说更容易理解。不过谢谢!

–詹森·邦廷
08年12月11日在17:21

window [“ funcName”]将返回未定义状态吗?这就是我目前遇到的问题。调用代码和函数在两个单独的js文件中定义。我尝试将它们添加到同一文件中,但是没有区别。

– codemonkey
10 Mar 16 '10在11:19

我认为这是一个问题。当您调用My.Namespace.functionName()时,它将引用My.Namespace对象。但是,当您调用executeFunctionByName(“ My.Namespace.functionName”,window)时,没有办法使它引用相同的东西。也许应该使用最后一个名称空间作为范围,如果没有名称空间,则使用窗口。或者,您可以允许用户将范围指定为参数。

– JW。
2011年7月6日在23:08



#2 楼

只是以为我会发布Jason Bunting的非常有用的函数的稍作改动的版本。

首先,我通过向slice()提供第二个参数简化了第一条语句。原始版本在IE以外的所有浏览器中都可以正常工作。其次,我在return语句中将其替换为上下文。否则,在执行目标函数时,它始终指向窗口。

function executeFunctionByName(functionName, context /*, args */) {
    var args = Array.prototype.slice.call(arguments, 2);
    var namespaces = functionName.split(".");
    var func = namespaces.pop();
    for (var i = 0; i < namespaces.length; i++) {
        context = context[namespaces[i]];
    }
    return context[func].apply(context, args);
}


评论


没有检查以查看“ functionName”是否实际存在?

– Crashalot
16年11月2日在1:08

我认为Mac的答案被低估了。我不是专家,但似乎经过深思熟虑并且很健壮。

–马丁·汉森·伦诺克斯(Martin Hansen Lennox)
17 Mar 9 '17 at 21:23

#3 楼

另一个问题的答案向您展示了如何做到这一点:与Python的locals()等效的Javascript?

基本上,您可以说

window["foo"](arg1, arg2);


或许多其他建议所建议的,您可以使用eval:

eval(fname)(arg1, arg2);


,尽管这非常不安全,除非您完全确定要评估的内容。

评论


第一种形式更可取

– annakata
08年12月11日15:54

当所有其他方法均失败时,仅将eval用作最后的手段。

–詹森·邦廷
08年12月11日在15:58

它是...但是它将与以下函数一起使用:x.y.z(args)吗?

–基隆
08年12月11日在15:58

@keiron:是的。在下面看到我的答案

– annakata
08年12月11日在16:02

#4 楼

您不仅可以这样做:

var codeToExecute = "My.Namespace.functionName()";
var tmpFunc = new Function(codeToExecute);
tmpFunc();


您还可以使用此方法执行任何其他JavaScript。

评论


当函数使用偶数参数时,也可以使用

–adeel41
2014年9月12日18:13

函数返回如何?

– Peter Denev
2014年10月31日在9:08

与eval(“ My.Namespace.functionName()”);有什么不同?

–developerbmw
2015年4月21日,0:36



@PeterDenev只需将第一行更改为var codeToExecute =“ return My.Namespace.functionName()”;

–developerbmw
2015年4月21日,0:40

@developerbmw,这是答案stackoverflow.com/questions/4599857/…

– Tejasvi Hegde
16-10-25在7:53



#5 楼

我认为,执行此操作的一种优雅方法是在哈希对象中定义函数。然后,您可以使用字符串从哈希中引用这些函数。例如,

var customObject = {
  customFunction: function(param){...}
};


然后您可以调用:

customObject['customFunction'](param);


其中customFunction是与定义的函数匹配的字符串在您的对象中。

评论


@ibsenv,谢谢您的评论,以帮助我确定此响应为最佳。我创建了一个函数对象数组,然后使用它来创建deferred.promises数组。我在下面放了一些示例代码。 (我不想创建新的答复并借用鲁本的答复。)

–user216661
16年1月8日在16:55



函数getMyData(arrayOfObjectsWithIds){var functionArray = arrayOfObjectsWithIds.map(function(value){return {myGetDataFunction:MyService.getMyData(value.id)};})var promises = functionArray.map(function(getDataFunction){var deferred = $ q.defer(); getDataFunction.myGetDataFunction.success(function(data){deferred.resolve(data)})。error(function(error){deferred.reject();}); return deferred.promise;}); $ q.all(promises).then(function(dataArray){//做东西})};

–user216661
16年1月8日在16:58

效果很好,我只添加下划线/破折号以验证其功能。然后跑

– elporfirio
16-09-21在16:18

#6 楼

使用ES6,您可以按名称访问类方法:

class X {
  method1(){
    console.log("1");
  }
  method2(){
    this['method1']();
    console.log("2");
  }
}
let x  = new X();
x['method2']();


输出将是:

1
2


评论


最好的JavaScript PURE ...天哪..删除类不起作用,但是还可以。谢谢!

– KingRider
16 Jun 3'at 13:51



这是我长期以来一直在寻找的东西。谢谢!

– PaladiN
17年5月22日在12:54



ES2015与此处无关。您可以使用纯对象或通过Object.create()进行原型委派来实现相同的目标。 const myObj = {method1(){console.log('1')},method2(){console.log('2')}} myObj ['method1'](); // 1 myObj ['method2'](); // 2

– sminutoli
18-10-26在2:54

这是黄金!!!令我惊讶的是,我从未想过。很好!!!

– thxmike
19年8月19日在1:39

我也认为这是实现我们目标的最捷径。

–克里斯·荣格
19年5月5日在15:50

#7 楼

两件事:


避免评估,这是非常危险和缓慢的。
其次,函数存在于哪里都没有关系,“全局” -ness无关紧要。可以通过x.y.foo()x.y['foo']()甚至x['y']['foo']()启用window['x']['y']['foo']()。您可以像这样无限期地链接。


评论


但是你不能用window ['x.y.z']()来调用x.y.z()

–nickf
08-12-11在16:11

#8 楼

所有答案都假定可以通过全局范围(窗口)访问这些功能。但是,OP并没有做这个假设。

如果函数存在于本地作用域(也称为闭包)中,并且未被其他本地对象引用,那么运气不好:您必须使用eval() AFAIK,请参见
在javascript中动态调用本地函数

评论


杜德(或dudette),非常感谢您指出这一点!我以为我快要疯了。

– Funktr0n
2014年3月16日下午3:13

#9 楼

根据您所在的位置,您还可以使用:

this["funcname"]();
self["funcname"]();
window["funcname"]();
top["funcname"]();
globalThis["funcname"]();


,或者在nodejs中

global["funcname"]()


#10 楼

您只需要通过window[<method name>]将字符串转换为指针即可。
示例:

var function_name = "string";
function_name = window[function_name];


现在您可以像指针一样使用它了。

评论


这似乎是一种更安全的方法。

–詹姆斯·普洛斯(James Poulose)
16 Mar 23 '16 at 16:20

#11 楼

这是我对杰森·邦廷(Jason Bunting)/亚历克斯·纳扎罗夫(Alex Nazarov)出色答案的贡献,其中包括了Crashalot要求的错误检查。
然后是以下函数:

a = function( args ) {
    console.log( 'global func passed:' );
    for( var i = 0; i < arguments.length; i++ ) {
        console.log( '-> ' + arguments[ i ] );
    }
};
ns = {};
ns.a = function( args ) {
    console.log( 'namespace func passed:' );
    for( var i = 0; i < arguments.length; i++ ) {
        console.log( '-> ' + arguments[ i ] ); 
    }
};
name = 'nsa';
n_s_a = [ 'Snowden' ];
noSuchAgency = function(){};


将允许您通过存储在字符串中的名称(包含名称空间或全局字符串)来调用javascript函数,带或不带参数(包括Array对象),提供有关遇到的任何错误(希望能够捕获它们)的反馈。

示例输出显示了其工作方式:

function executeFunctionByName( functionName, context /*, args */ ) {
    var args, namespaces, func;

    if( typeof functionName === 'undefined' ) { throw 'function name not specified'; }

    if( typeof eval( functionName ) !== 'function' ) { throw functionName + ' is not a function'; }

    if( typeof context !== 'undefined' ) { 
        if( typeof context === 'object' && context instanceof Array === false ) { 
            if( typeof context[ functionName ] !== 'function' ) {
                throw context + '.' + functionName + ' is not a function';
            }
            args = Array.prototype.slice.call( arguments, 2 );

        } else {
            args = Array.prototype.slice.call( arguments, 1 );
            context = window;
        }

    } else {
        context = window;
    }

    namespaces = functionName.split( "." );
    func = namespaces.pop();

    for( var i = 0; i < namespaces.length; i++ ) {
        context = context[ namespaces[ i ] ];
    }

    return context[ func ].apply( context, args );
}


评论


不知道...这是非常好的努力。但是听起来对我来说太宽泛了...

– TechNyquist
17 Mar 29 '17在9:33

?? SO是一个问题/答案/教学平台。我将很高兴提供我能想到的所有示例,以期希望能传达照明。对我来说,这就是重点。

– Mac
17年12月8日在18:18

如果仍然要评估functionName,为什么不使用它呢?

–数据
18-09-27在8:46

这对我不起作用。我有一个命名空间函数a.b.c.d,其中d是函数名称。调用executeFunctionByName(“ abcd”,window)在检查if(typeof context [functionName]!=='function')的行上失败,因为上下文-window-被定义为对象和数组,但是window ['abcd ']不存在,因为在接受的答案中被确定为问题:window [“ My.Namespace.functionName”](参数); //失败

–akousmata
19年5月9日在12:39

#12 楼

如果要使用window["functionName"]调用对象的函数而不是全局函数。您可以这样做;

var myObject=new Object();
myObject["functionName"](arguments);


示例:

var now=new Date();
now["getFullYear"]()


#13 楼

请务必小心!

一个人应避免使用JavaScript在字符串中调用函数的原因有两个:

原因1:某些代码混淆器会破坏您的代码,因为它们会破坏代码更改函数名称,使字符串无效。

原因2:使用这种方法的代码很难维护,因为查找字符串调用的方法的用法要困难得多。

#14 楼

这是我的Es6方法,使您可以通过名称作为字符串或函数名称来调用函数,还可以将不同数量的参数传递给不同类型的函数:




 function fnCall(fn, ...args)
{
  let func = (typeof fn =="string")?window[fn]:fn;
  if (typeof func == "function") func(...args);
  else throw new Error(`${fn} is Not a function!`);
}


function example1(arg1){console.log(arg1)}
function example2(arg1, arg2){console.log(arg1 + "  and   " + arg2)}
function example3(){console.log("No arguments!")}

fnCall("example1", "test_1");
fnCall("example2", "test_2", "test3");
fnCall(example3);
fnCall("example4"); // should raise an error in console 




#15 楼

惊讶地发现没有提到setTimeout。

要运行没有参数的函数:

var functionWithoutArguments = function(){
    console.log("Executing functionWithoutArguments");
}
setTimeout("functionWithoutArguments()", 0);


要运行带有参数的函数:

var functionWithArguments = function(arg1, arg2) {
    console.log("Executing functionWithArguments", arg1, arg2);
}
setTimeout("functionWithArguments(10, 20)");


要深入运行命名空间功能:

var _very = {
    _deeply: {
        _defined: {
            _function: function(num1, num2) {
                console.log("Execution _very _deeply _defined _function : ", num1, num2);
            }
        }
    }
}
setTimeout("_very._deeply._defined._function(40,50)", 0);


评论


这不能为问题提供答案。要批评或要求作者澄清,请在其帖子下方留下评论-您始终可以对自己的帖子发表评论,一旦您拥有足够的声誉,就可以在任何帖子中发表评论。

– AstroCB
14-10-17在20:57

请添加一个示例,说明如何使用一些参数调用runMe。

–lexicore
14-10-17在21:01

@lexicore我在评论队列中对删除进行了投票,因为它显然不能为问题提供实质性的答案,而且它本身没有什么价值。

– AstroCB
2014-10-17 21:22



此方法可能存在巨大的缺陷,因为它将执行置于渲染队列的末尾,从而使此调用异步

– PeterM
16年11月15日在10:27

我喜欢这个答案,它似乎可以满足我的要求。

–金顿
18-09-18在9:27

#16 楼

我认为您不需要复杂的中间函数或eval也不依赖于诸如window之类的全局变量:
 function fun1(arg) {
  console.log(arg);
}

function fun2(arg) {
  console.log(arg);
}

const operations = {
  fun1,
  fun2
};

operations["fun1"]("Hello World");
operations.fun2("Hello World");

// You can use intermediate variables, if you like
let temp = "fun1";
operations[temp]("Hello World");
 

使用导入的功能:
 // mode.js
export function fun1(arg) {
  console.log(arg);
}

export function fun2(arg) {
  console.log(arg);
}
 

 // index.js
import { fun1, fun2 } from "./mod";

const operations = {
  fun1,
  fun2
};

operations["fun1"]("Hello World");
operations["fun2"]("Hello World");
 

由于它正在使用属性访问,因此它将在最小化或混淆中幸存下来,这与您在此处找到的一些答案相反。

#17 楼

因此,就像其他人所说的,绝对最好的选择是:

window['myfunction'](arguments)


所以这是我的函数版本,它将按名称执行所有函数(包括或不包括对象):




 my = {
    code : {
        is : {
            nice : function(a, b){ alert(a + "," + b); }
        }
    }
};

guy = function(){ alert('awesome'); }

function executeFunctionByName(str, args)
{
    var arr = str.split('.');
    var fn = window[ arr[0] ];
    
    for (var i = 1; i < arr.length; i++)
    { fn = fn[ arr[i] ]; }
    fn.apply(window, args);
}

executeFunctionByName('my.code.is.nice', ['arg1', 'arg2']);
executeFunctionByName('guy'); 




#18 楼

  let t0 = () => { alert('red0') }
  var t1 = () =>{ alert('red1') }
  var t2 = () =>{ alert('red2') }
  var t3 = () =>{ alert('red3') }
  var t4 = () =>{ alert('red4') }
  var t5 = () =>{ alert('red5') }
  var t6 = () =>{ alert('red6') }

  function getSelection(type) {
    var evalSelection = {
      'title0': t0,
      'title1': t1,
      'title2': t2,
      'title3': t3,
      'title4': t4,
      'title5': t5,
      'title6': t6,
      'default': function() {
        return 'Default';
      }
    };
    return (evalSelection[type] || evalSelection['default'])();
  }
  getSelection('title1');


更多OOP解决方案...

#19 楼

有关Jason和Alex帖子的更多详细信息。我发现将默认值添加到上下文很有帮助。只需将context = context == undefined? window:context;放在函数的开头即可。您可以将window更改为首选上下文,然后每次在默认上下文中调用此变量时都不需要传递相同的变量。

#20 楼

要添加到Jason Bunting的答案中,如果您使用的是nodejs或其他内容(并且在dom js中也适用),则可以使用this而不是window(并记住:eval是邪恶的:

this['fun'+'ctionName']();


#21 楼

我的代码中有一个非常相似的内容。
我有一个服务器生成的字符串,其中包含一个函数名,我需要将该函数名作为第三方库的回调传递。因此,我有一个接受字符串并向函数返回“指针”的代码,如果找不到则返回null。

我的解决方案与“ Jason Bunting的非常有用的函数”非常相似,尽管它不会自动执行,并且上下文始终在窗口中。但这很容易修改。

希望对某人有所帮助。

/**
 * Converts a string containing a function or object method name to a function pointer.
 * @param  string   func
 * @return function
 */
function getFuncFromString(func) {
    // if already a function, return
    if (typeof func === 'function') return func;

    // if string, try to find function or method of object (of "obj.func" format)
    if (typeof func === 'string') {
        if (!func.length) return null;
        var target = window;
        var func = func.split('.');
        while (func.length) {
            var ns = func.shift();
            if (typeof target[ns] === 'undefined') return null;
            target = target[ns];
        }
        if (typeof target === 'function') return target;
    }

    // return null if could not parse
    return null;
}


#22 楼

还有一些非常有用的方法。

http://devlicio.us/blogs/sergio_pereira/archive/2009/02/09/javascript-5-ways-to-call-a-function.aspx

var arrayMaker = {  
    someProperty: 'some value here',  
    make: function (arg1, arg2) {  
        return [ this, arg1, arg2 ];  
    },
    execute: function_name
};


#23 楼

我无法抗拒提及另一个技巧,如果您有数量不明的参数也作为包含函数名称的字符串的一部分传递,这将很有帮助。例如:

var annoyingstring = 'call_my_func(123, true, "blah")';

如果Javascript在HTML页面上运行,则只需要一个不可见的链接;您可以将字符串传递到onclick属性,然后调用click方法。

<a href="#" id="link_secret"><!-- invisible --></a>

$('#link_secret').attr('onclick', annoyingstring);
$('#link_secret').click();


或在运行时创建<a>元素。

评论


创新的解决方案,但这不适用于对象或数组类型参数。

–丹尼斯·海登(Dennis Heiden)
16-10-11在9:42

这是在引擎盖下使用eval。。。

–胡安·门德斯(Juan Mendes)
17年5月25日在21:40

#24 楼

最简单的方法是像访问元素那样访问它

window.ClientSideValidations.forms.location_form




window.ClientSideValidations.forms['location_form']

相同

#25 楼

您也可以在eval("functionname as string")中调用javascript函数。如下所示:(eval是纯JavaScript函数)

function testfunc(){
    return "hello world";
}

$( document ).ready(function() {

     $("div").html(eval("testfunc"));
});


工作示例:https://jsfiddle.net/suatatan/24ms0fna/4/

评论


这工作正常,非常简单

–卡洛斯E
17-10-16在16:29

而且真的很慢。

–马可
'18 Sep 1'在15:11

#26 楼

这对我有用:

var command = "Add";
var tempFunction = new Function("Arg1","Arg2", "window." + command + "(Arg1,Arg2)");
tempFunction(x,y);


我希望这行得通。

#27 楼

如果不使用eval('function()'),则可以使用new Function(strName)创建新功能。以下代码已使用FF,Chrome,IE进行了测试。

<html>
<body>
<button onclick="test()">Try it</button>
</body>
</html>
<script type="text/javascript">

  function test() {
    try {    
        var fnName = "myFunction()";
        var fn = new Function(fnName);
        fn();
      } catch (err) {
        console.log("error:"+err.message);
      }
  }

  function myFunction() {
    console.log('Executing myFunction()');
  }

</script>


#28 楼

use this

function executeFunctionByName(functionName, context /*, args */) {
      var args = [].slice.call(arguments).splice(2);
      var namespaces = functionName.split(".");
      var func = namespaces.pop();
      for(var i = 0; i < namespaces.length; i++) {
        context = context[namespaces[i]];
      }
      return context[func].apply(context, args);
    }


评论


为什么?没有解释的答案很可能是无用的。

–丹尼尔·W。
16年11月11日在16:49

#29 楼

基本外观:

var namefunction = 'jspure'; // String

function jspure(msg1 = '', msg2 = '') { 
  console.log(msg1+(msg2!=''?'/'+msg2:''));
} // multiple argument

// Results ur test
window[namefunction]('hello','hello again'); // something...
eval[namefunction] = 'hello'; // use string or something, but its eval just one argument and not exist multiple


存在其他类型的函数是类,请参见示例nils petersohn

#30 楼

感谢您提供非常有帮助的答案。我在项目中使用Jason Bunting的功能。

我扩展了它以使其与可选的超时一起使用,因为设置超时的常规方法不起作用。请参阅abhishekisnot的问题




 function executeFunctionByName(functionName, context, timeout /*, args */ ) {
	var args = Array.prototype.slice.call(arguments, 3);
	var namespaces = functionName.split(".");
	var func = namespaces.pop();
	for (var i = 0; i < namespaces.length; i++) {
		context = context[namespaces[i]];
	}
	var timeoutID = setTimeout(
		function(){ context[func].apply(context, args)},
		timeout
	);
    return timeoutID;
}

var _very = {
    _deeply: {
        _defined: {
            _function: function(num1, num2) {
                console.log("Execution _very _deeply _defined _function : ", num1, num2);
            }
        }
    }
}

console.log('now wait')
executeFunctionByName("_very._deeply._defined._function", window, 2000, 40, 50 );