我有一个JavaScript函数名的字符串,如何将其转换为函数指针以便稍后调用?
根据情况,我可能需要将各种参数传递到方法中。
一些函数可能采用namespace.namespace.function(args[...])
的形式。
我有一个JavaScript函数名的字符串,如何将其转换为函数指针以便稍后调用?
根据情况,我可能需要将各种参数传递到方法中。
一些函数可能采用namespace.namespace.function(args[...])
的形式。
除非你绝对没有其他选择,否则不要使用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);
我想分享一下稍微修改过的Jason Bunting非常有用的函数。
首先,我通过向slice()提供第二个参数来简化了第一个语句。原始版本在除IE外的所有浏览器中都可以正常工作。
其次,在返回语句中,我用context替换了this;否则,在执行目标函数时,this总是指向window。
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);
}
context[func];
,让调用者传递参数:
getFuncByName(functionName, context)(arg1,arg2)
这样它就会使用与 eval 相同的定义。 - Omuwindow["foo"](arg1, arg2);
或者像许多其他人建议的那样,您可以使用eval:
eval(fname)(arg1, arg2);
window
选项在像Node这样的服务器环境中根本不起作用。
在这种情况下,eval
可能是最好和最快的选择。 - Jacopo Pace我认为一种优雅的方法是通过在哈希对象中定义函数。然后,您可以使用字符串从哈希中引用这些函数。
var customObject = {
customFunction: function(param){...}
};
然后您可以调用:
customObject['customFunction'](param);
自定义函数将是一个字符串,与您的对象中定义的函数匹配。
更新
看起来这个答案对很多程序员有帮助,因此这里提供一个更新版本。
使用ES6,您还可以使用计算属性名,这将使您避免使用魔术字符串。
const FunctionNames = Object.freeze({
FirstFunction: "firstFunction",
SecondFunction: "secondFunction"
});
...
var customObject = {
[FunctionNames.FirstFunction]: function(param){...},
[FunctionNames.SecondFunction]: function(param){...}
};
...
customObject[FunctionNames.FirstFunction](param);
你不能只是这样做吗:
var codeToExecute = "My.Namespace.functionName()";
var tmpFunc = new Function(codeToExecute);
tmpFunc();
eval("My.Namespace.functionName()");
相比,这有何不同? - brettwhitemanvar codeToExecute = "return My.Namespace.functionName()";
- brettwhiteman使用 ES6,您可以通过名称访问类方法:
class X {
method1(){
console.log("1");
}
method2(){
this['method1']();
console.log("2");
}
}
let x = new X();
x['method2']();
输出结果将会是:
1
2
Object.create()
进行原型委托来实现相同的目标。const myObj = {
method1() { console.log('1') },
method2() { console.log('2') }
}
myObj'method1'; // 1
myObj'method2'; // 2 - sminutoli两件事:
避免使用eval,它非常危险且缓慢。
其次,函数存在的位置并不重要,“全局”性质是无关紧要的。“x.y.foo()”可以通过“x.y['foo']()”或“x['y']['foo']()”甚至“window['x']['y']['foo']()”来启用。您可以像这样无限链接。
所有答案都假设函数可以通过全局作用域(window)访问。然而,OP没有做出这个假设。
如果函数存在于本地作用域(也称为闭包)中且未被其他本地对象引用,则很不幸:您必须使用eval()
,据我所知,请参见在JavaScript中动态调用本地函数
function myLocalOwn() {}; window.myLocalOwn = myLocalOwn;
- undefined根据您所在的位置,您也可以使用:
this["funcname"]();
self["funcname"]();
window["funcname"]();
top["funcname"]();
globalThis["funcname"]();
或者,在nodejs中
global["funcname"]()
function callObjectMethod(obj,meth){ return (_v) => { obj[meth](_v) } }
。对我来说,这对于使用通过外部服务回调的参数调用某些对象方法非常有用。希望这能帮助其他人。 - Enrique René这是我的对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(){};
然后是下面的函数:
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 );
}
这将允许您通过存储在字符串中的名称(包括带有命名空间或全局的名称),调用JavaScript函数,带或不带参数(包括数组对象),并提供有关遇到的任何错误的反馈(希望能捕获它们)。
示例输出显示了它如何工作:
// calling a global function without parms
executeFunctionByName( 'a' );
/* OUTPUT:
global func passed:
*/
// calling a global function passing a number (with implicit window context)
executeFunctionByName( 'a', 123 );
/* OUTPUT:
global func passed:
-> 123
*/
// calling a namespaced function without parms
executeFunctionByName( 'ns.a' );
/* OUTPUT:
namespace func passed:
*/
// calling a namespaced function passing a string literal
executeFunctionByName( 'ns.a', 'No Such Agency!' );
/* OUTPUT:
namespace func passed:
-> No Such Agency!
*/
// calling a namespaced function, with explicit context as separate arg, passing a string literal and array
executeFunctionByName( 'a', ns, 'No Such Agency!', [ 007, 'is the man' ] );
/* OUTPUT:
namespace func passed:
-> No Such Agency!
-> 7,is the man
*/
// calling a global function passing a string variable (with implicit window context)
executeFunctionByName( 'a', name );
/* OUTPUT:
global func passed:
-> nsa
*/
// calling a non-existing function via string literal
executeFunctionByName( 'n_s_a' );
/* OUTPUT:
Uncaught n_s_a is not a function
*/
// calling a non-existing function by string variable
executeFunctionByName( n_s_a );
/* OUTPUT:
Uncaught Snowden is not a function
*/
// calling an existing function with the wrong namespace reference
executeFunctionByName( 'a', {} );
/* OUTPUT:
Uncaught [object Object].a is not a function
*/
// calling no function
executeFunctionByName();
/* OUTPUT:
Uncaught function name not specified
*/
// calling by empty string
executeFunctionByName( '' );
/* OUTPUT:
Uncaught is not a function
*/
// calling an existing global function with a namespace reference
executeFunctionByName( 'noSuchAgency', ns );
/* OUTPUT:
Uncaught [object Object].noSuchAgency is not a function
*/
if(typeof context [functionName]!== 'function')
的行上失败,因为上下文 - 窗口 - 被定义为对象和数组,但window ['a.b.c.d']不存在,正如在接受的答案中所确定的问题:“window [“ My.Namespace.functionName”](arguments); //失败”。 - akousmata
My.Namespace.functionName()
时,this
将指向My.Namespace
对象。但是,当你调用executeFunctionByName("My.Namespace.functionName", window)
时,没有办法使this
指向相同的对象。也许它应该使用最后一个命名空间作为作用域,或者如果没有命名空间,则使用window
。或者你可以允许用户将作用域指定为参数。 - JW.