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

根据具体情况,我可能还需要将各种参数传递到方法中。

一些函数可以采用namespace.namespace.function(args[…])的形式。


当前回答

我只是想发布一个稍微改变了的Jason Bunting非常有用的函数。

首先,我通过向slice()提供第二个参数简化了第一个语句。最初的版本在除IE之外的所有浏览器中都运行良好。

其次,我在return语句中用context替换了它;否则,在执行目标函数时,它总是指向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);
}

其他回答

如果你想用window["functionName"]调用一个对象的函数而不是全局函数。你可以这样做;

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

例子:

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

由于eval()是邪恶的,而new Function()不是最有效的方法来实现这一点,这里有一个快速的JS函数,从它的字符串名称返回函数。

适用于命名空间的函数 在null/undefined字符串的情况下回退到null函数 如果没有找到函数,则回退到null函数


    function convertStringtoFunction(functionName){

        var nullFunc = function(){}; // Fallback Null-Function
        var ret = window; // Top level namespace

        // If null/undefined string, then return a Null-Function
        if(functionName==null) return nullFunc;

        // Convert string to function name
        functionName.split('.').forEach(function(key){ ret = ret[key]; });

        // If function name is not available, then return a Null-Function else the actual function
        return (ret==null ? nullFunc : ret);

    }

用法:


    convertStringtoFunction("level1.midLevel.myFunction")(arg1, arg2, ...);

谢谢你非常有用的回答。我在我的项目中使用了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 );

以下是我对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
  */

不要使用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);