当我将其名称作为字符串时如何执行 JavaScript 函数

IT技术 javascript
2021-01-04 16:38:34

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

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

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

6个回答

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);
我认为这里有问题。当您调用 时My.Namespace.functionName()this将引用该My.Namespace对象。但是当您调用 时executeFunctionByName("My.Namespace.functionName", window),就无法this引用相同的内容。也许它应该使用最后一个命名空间作为范围,或者window如果没有命名空间。或者您可以允许用户将范围指定为参数。
2021-02-13 16:38:34
你知道你不需要整个“func”结构吗?单独的“context.apply”就可以了
2021-02-14 16:38:34
从头开始 - 代码足够清晰,知道的人都知道。如果您像我一样,并且知道自己在做什么,那么如果您使用了此代码,则可以自行进行此类更改。Stack Overflow 是为了教育别人,我觉得我的代码对于新手来说更容易理解。不过还是谢谢!
2021-02-21 16:38:34
是否存在 window["funcName"] 返回 undefined 的情况?这就是我目前遇到的问题。调用代码和函数定义在两个单独的 js 文件中。我尝试将它们添加到同一个文件中,但没有任何区别。
2021-03-02 16:38:34
当然,我知道这一点——但我编写函数的方式为那些阅读它的人提供了一些清晰度,这些人可能无法完全理解正在发生的事情。我写了这个函数,意识到阅读它的人可能需要一些帮助。我会提供一个替代方案,因为你问...
2021-03-05 16:38:34

只是想我会发布一个稍微改动过的Jason Bunting 非常有用的功能的版本

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

其次,我在 return 语句中用上下文替换了否则,当执行目标函数时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);
}
我认为 Mac 的回答被低估了。我不是专家,但它似乎经过深思熟虑和强大。
2021-02-07 16:38:34
没有检查“functionName”是否确实存在?
2021-02-17 16:38:34

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

基本上,你可以说

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

或者正如许多其他人所建议的那样,您可以只使用 eval:

eval(fname)(arg1, arg2);

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

第一种形式更可取
2021-02-12 16:38:34
@keiron:是的。请看下面我的回答
2021-02-24 16:38:34
它是......但是它可以与这样的函数一起使用:xyz(args)?
2021-02-26 16:38:34
当所有其他方法都失败时,仅将 eval 用作最后的手段。
2021-03-07 16:38:34

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

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

然后你可以调用:

customObject['customFunction'](param);

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

更新

似乎这个答案对那里的许多编码人员很有帮助,所以这里有一个更新的版本。

使用 ES6,您还可以使用计算属性名称,这将允许您避免魔术字符串。

const FunctionNames = Object.freeze({ 
  FirstFunction: "firstFunction", 
  SecondFunction: "secondFunction" 
});

...

var customObject = {
  [FunctionNames.FirstFunction]: function(param){...},
  [FunctionNames.SecondFunction]: function(param){...}
};

...

customObject[FunctionNames.FirstFunction](param);

@ibsenv,感谢您的评论帮助我确定此回复是最佳回复。我创建了一个函数对象数组,然后用它来创建一个 deferred.promises 数组。我在下面放了一些示例代码。(我不想创建新的回复并借用鲁本的回复。)
2021-02-07 16:38:34
function 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) { //做东西 }) };
2021-02-08 16:38:34
这很好用,我只添加下划线/lodash 来验证它是否是一个函数。然后运行
2021-02-08 16:38:34

你能不能不这样做:

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

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

函数返回呢?
2021-02-22 16:38:34
当参数与函数一起传递时有效
2021-02-26 16:38:34
@developerbmw,这是答案stackoverflow.com/questions/4599857/...
2021-02-27 16:38:34
那与 有eval("My.Namespace.functionName()");什么不同
2021-03-03 16:38:34
@PeterDenev 只是将第一行更改为 var codeToExecute = "return My.Namespace.functionName()";
2021-03-08 16:38:34