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

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

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


当前回答

在我的代码中有一个非常相似的东西。 我有一个服务器生成的字符串,其中包含一个函数名,我需要作为第三方库的回调传递。所以我有一个代码,接受字符串并返回一个指向函数的“指针”,如果没有找到,则为空。

我的解决方案非常类似于“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;
}

其他回答

这里有几个executeByName函数,它们工作得很好,除非name包含方括号——这是我遇到的问题——因为我有动态生成的名称。因此,上述函数将失败的名称

小部件应用。[toggleFolders’‘872LfCHc] []

作为补救措施,我也考虑了这一点,也许有人会发现它很有用:

由CoffeeScript生成:

var executeByName = function(name, context) {
  var args, func, i, j, k, len, len1, n, normalizedName, ns;
  if (context == null) {
    context = window;
  }
  args = Array.prototype.slice.call(arguments, 2);
  normalizedName = name.replace(/[\]'"]/g, '').replace(/\[/g, '.');
  ns = normalizedName.split(".");
  func = context;
  for (i = j = 0, len = ns.length; j < len; i = ++j) {
    n = ns[i];
    func = func[n];
  }
  ns.pop();
  for (i = k = 0, len1 = ns.length; k < len1; i = ++k) {
    n = ns[i];
    context = context[n];
  }
  if (typeof func !== 'function') {
    throw new TypeError('Cannot execute function ' + name);
  }
  return func.apply(context, args);
}

为了更好的可读性检查CoffeeScript版本:

executeByName = (name, context = window) ->
    args = Array.prototype.slice.call(arguments, 2)
    normalizedName = name.replace(/[\]'"]/g, '').replace(/\[/g, '.')
    ns = normalizedName.split "."
    func = context
    for n, i in ns
        func = func[n]

    ns.pop()
    for n, i in ns
        context = context[n];
    if typeof func != 'function'
        throw new TypeError 'Cannot execute function ' + name
    func.apply(context, args)

小心! !

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

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

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

下面是我最终为我的一个项目实现的一个健壮且可重用的解决方案。

一个FunctionExecutor构造函数

用法:

let executor = new FunctionExecutor();
executor.addFunction(two)
executor.addFunction(three)

executor.execute("one");
executor.execute("three");

显然,在项目中,所有需要按名称调用的函数的添加都是通过循环完成的。

函数Executor:

function FunctionExecutor() {
  this.functions = {};

  this.addFunction = function (fn) {
    let fnName = fn.name;
    this.functions[fnName] = fn;
  }

  this.execute = function execute(fnName, ...args) {
    if (fnName in this.functions && typeof this.functions[fnName] === "function") {
      return this.functions[fnName](...args);
    }
    else {
      console.log("could not find " + fnName + " function");
    }
  }

  this.logFunctions = function () {
    console.log(this.functions);
  }
}

使用示例:

function two() {
  console.log("two"); 
}

function three() {
  console.log("three");
}

let executor = new FunctionExecutor();
executor.addFunction(two)
executor.addFunction(three)

executor.execute("one");
executor.execute("three");

这个其他问题的答案向您展示了如何做到这一点:Javascript相当于Python的locals()?

基本上,你可以说

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

或者像其他人建议的那样,你可以使用eval:

eval(fname)(arg1, arg2);

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

两件事:

避免评估,这是非常危险和缓慢的 其次,函数在哪里并不重要,“全局性”是无关紧要的。x.y.foo()可以通过x.y(“foo”)()或x (y)(“foo”)()甚至窗口[x] [y](“foo”)()。你可以像这样无限地链。