当前位置:  开发笔记 > 编程语言 > 正文

当我的名字作为字符串时,如何执行JavaScript函数

如何解决《当我的名字作为字符串时,如何执行JavaScript函数》经验,为你挑选了15个好方法。

我在JavaScript中将函数的名称作为字符串.如何将其转换为函数指针,以便稍后调用?

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

一些功能可能采取的形式namespace.namespace.function(args[...]).



1> Jason Buntin..:

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


从头开始 - 代码很清楚,知道的代码知道了.如果您像我一样,并且知道自己在做什么,那么如果您使用此代码,则可以自行进行此类更改.Stack Overflow用于教育他人,我认为我的代码更容易让新手理解.谢谢!
当然,我知道 - 但是我写这个函数的方式为那些阅读它的人提供了一些清晰度,可能并不能完全理解正在发生的事情.我写了这个函数,意识到阅读它的人可能需要一些帮助.我会提供一个替代,因为你问...
我觉得这里有问题.当你调用`My.Namespace.functionName()`时,`this`将引用`My.Namespace`对象.但是当你调用`executeFunctionByName("My.Namespace.functionName",window)`时,就没有办法让`this`引用相同的东西.也许它应该使用最后一个命名空间作为范围,或者如果没有命名空间则使用`window`.或者您可以允许用户将范围指定为参数.
你知道你不需要整个"func"构造吗?单独"context.apply"就可以了
是否存在window ["funcName"]返回undefined的情况?这就是我现在遇到的问题.调用代码和函数在两个单独的js文件中定义.我尝试将它们添加到同一个文件中但没有区别.
在javascript 1.8中你可以做`functionName.split('.').reduce(function(obj,key){return obj [key];},window);`
只有将它放入全局范围时,`executeFunctionByName`才有效.如果你不这样做,你会得到`Uncaught TypeError:Illegal invocation`.我认为最后一行`return context [func] .apply(this,args);`应该是`return context [func] .apply(window,args);`
@brentonstrine再试一次,不用onload包装javascript代码:http://jsfiddle.net/pgpLmdwn/

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


我提供了一个包括错误检查的答案。

3> Eli Courtwri..:

这个问题的答案告诉你如何做到这一点:Javascript相当于Python的本地人()?

基本上,你可以说

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

或许多其他人建议,你可以使用eval:

eval(fname)(arg1, arg2);

虽然这是非常不安全的,除非你完全确定你正在评估什么.


当其他所有方法都失败时,只使用eval作为最后的手段.
第一种形式是更可取的

4> 小智..:

你能不能这样做:

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

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


这与`eval("My.Namespace.functionName()")有什么不同?`?
甚至在使用函数传递参数时也能正常工作
@developerbmw,这里是答案http://stackoverflow.com/questions/4599857/are-eval-and-new-function-the-same-thing

5> 小智..:

我认为这样做的一种优雅方式是在哈希对象中定义函数.然后,您可以使用字符串从哈希中引用这些函数.例如

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

然后你可以打电话:

customObject['customFunction'](param);

其中customFunction将是与对象中定义的函数匹配的字符串.



6> nils peterso..:

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

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

输出将是:

1
2



7> annakata..:

两件事情:

避免评估,它非常危险和缓慢

其次,你的功能存在于哪里并不重要,"全球" - 无关紧要.x.y.foo()可通过启用x.y['foo']()x['y']['foo']()甚至window['x']['y']['foo']().你可以像这样无限期地链接.



8> Wolfgang Kue..:

所有答案都假设可以通过全局范围(aka窗口)访问这些函数.然而,OP没有做出这个假设.

如果函数存在于本地范围(也就是闭包)并且没有被其他一些本地对象引用,那么运气不好:你必须使用eval() AFAIK,看看 在javascript中动态调用本地函数


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

9> 小智..:

您只需要将字符串转换为指针window[].例:

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

现在你可以像指针一样使用它.



10> Mac..:

以下是我对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函数,无论是命名空间还是全局,带或不带参数(包括Array对象),提供有关遇到的任何错误的反馈(希望能够捕获它们).

示例输出显示了它的工作原理:

// 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
  */



11> Ahmet DAL..:

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

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

例:

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



12> Zibri..:

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

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

或者,在nodejs中

global["funcname"]()



13> 小智..:

小心!!!

应该尽量避免在JavaScript中通过字符串调用函数,原因有两个:

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

原因2:维​​护使用此方法的代码要困难得多,因为找到字符串调用的方法的用法要困难得多.



14> pouyan..:

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

function fnCall(fn, ...args)
{
  let func = (typeof fn =="string")?window[fn]:fn;
  if (typeof func == "function") func(...args)
  else console.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> abhishekisno..:

很惊讶没有提到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);

推荐阅读
路人甲
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有