在javascript中动态调用本地函数

Posted

技术标签:

【中文标题】在javascript中动态调用本地函数【英文标题】:dynamically call local function in javascript 【发布时间】:2012-03-16 22:05:05 【问题描述】:

关于通过名称动态调用函数有很多类似的问题。但是,我无法找到解决我的特定问题的解决方案,即我在闭包中拥有本地函数而不将函数暴露给我的对象的公共接口。

让我们看一些代码(这是一个虚构的例子)...

(function(window,$) 

  MyObject = (function($) 
    var obj = ;
    obj.publicMethod = function(number,otherarg) 
      this['privateMethod'+number].apply(this,[otherarg]);
    ;

    var privateMethod1 = function(arg) 
      //do something with arg
    ;

    var privateMethod2 = function(arg) 
      //do something else with arg
    ;

    return obj;
  )($);

  window.MyObject = MyObject;
)(window,jQuery);

这不起作用,因为“this”是 MyObject 并且本地函数未公开。 此外,我希望能够在尝试调用它之前检查该函数是否存在。 例如。

var func_name = 'privateMethod'+number;
if($.isFunction(this[func_name])) 
  this[func_name].apply(this,[otherarg]);

我不确定如何继续,除了将我的私有函数暴露给公共接口之外,一切正常。

obj.privateMethod1 = function(arg) 
  //do something with arg
;

obj.privateMethod2 = function(arg) 
  //do something else with arg
;

我的想法已经不多了。非常感谢您的帮助和建议。

【问题讨论】:

【参考方案1】:

私有函数是局部变量而不是任何对象的一部分。因此,用于访问属性的 [...] 符号永远不会起作用,因为没有对象是私有函数的属性。

相反,您可以创建两个对象:privatepublic

var public  = ,
    private = ;

public.publicMethod = function(number, otherarg) 
  // `.apply` with a fixed array can be replaced with `.call`
  private['privateMethod' + number].call(this, otherarg);
;

private.privateMethod1 = function(arg) 
  //do something with arg
;

private.privateMethod2 = function(arg) 
  //do something else with arg
;

return public; // expose public, but not private

【讨论】:

这么直截了当...我一直在唱这个咒语,以至于我忘记了它的意思。【参考方案2】:

您无法通过字符串获取对局部变量的引用。您必须将本地对象添加到命名空间:

(function(window,$) 
  // Use "var MyObject = " instead of "MyObject = "!! Otherwise, you're assigning
  //  the object to the closest parent declaration of MyVar, instead of locally!
  var MyObject = (function($) 
    var obj = ;
    var local = ;  // <-- Local namespace
    obj.publicMethod = function(number,otherarg) 
      local['privateMethod'+number].call(this, otherarg);
    ;

    var privateMethod1 = local.privateMethod1 = function(arg) 
      //do something with arg
    ;

    var privateMethod2 = local.privateMethod2 = function(arg) 
      //do something else with arg
    ;

    return obj;
  )($);

  window.MyObject = MyObject;
)(window,jQuery);

【讨论】:

澄清一下,您不再需要别名声明 var privateMethodX,因为它们是 local 的一部分;我假设他们仍然在这个例子中进行比较。【参考方案3】:

我很惊讶不正确的答案被标记为已接受。实际上,您可以通过字符串获取对局部变量的引用。只需使用eval

(function(window,$) 

    MyObject = (function($) 
        var obj = ;
        obj.publicMethod = function(number,otherarg) 

            // Gets reference to a local variable
            var method = eval('privateMethod'+number);

            // Do with it whatever you want
            method.apply(this,[otherarg]);
        ;

        var privateMethod1 = function(arg) 
            //do something with arg
        ;

        var privateMethod2 = function(arg) 
            //do something else with arg
        ;

        return obj;
    )($);

    window.MyObject = MyObject;
)(window,jQuery);

实际上这段代码非常糟糕,在 99.9% 的情况下你不应该使用eval。但是你必须知道它是如何工作的以及你可以用它做什么。当需要使用eval 时,我自己也遇到过一些非常具体的情况。

【讨论】:

这个问题很旧,但是,接受的答案有什么问题?它被广泛接受为 javascript 对象上公共/私有方法的正确方法。 其实我的抱怨是反对“你不能通过字符串获得对局部变量的引用”。这不是真的,你可以。正如我所写:使用eval 是非常糟糕的做法,但您必须知道如何使用它。使用eval,您可以通过字符串访问局部变量。我认为这个答案可能会误导其他 javascript 用户。答案的另一部分怎么样 - 它是正确的(虽然我认为@pimvdb 变体更好一点,但这并不重要)。【参考方案4】:

您不能从定义它们的范围之外调用这些函数这一事实是 javascript 的一个基本部分,事实上,所有编程语言也是如此。

调用这些函数的唯一方法是将它们公开。然而,可以改为应用基于约定的方法。下划线前缀相当普遍,通常被理解为“不打算作为公共函数调用”,例如:

obj._privateMethod1 = function(arg) 
  //...
;

【讨论】:

【参考方案5】:

假设您只有几个函数要调用,您可以创建自己的 Window 版本来调用这些函数:

var myFuncs = 
    'foo': foo,
    'bar': bar
;

然后在你的代码中:

var s = 'foo';
myFuncs[s]();

只需确保在将函数添加到对象时定义它们即可。在加载时函数不存在的模块中,您可以在模块初始化时添加它们:

var myFuncs = ;
var init = function()
    myFuncs['foo'] = foo;
    myFuncs['bar'] = bar;

【讨论】:

以上是关于在javascript中动态调用本地函数的主要内容,如果未能解决你的问题,请参考以下文章

使用动态数量的参数调用动态函数[重复]

Asp.net MVC 5 动态创建按钮并调用带有参数的 javascript 函数

JavaScript之 ------ 函数(一般函数动态函数匿名函数)

在Django中加载网页后调用动态python函数

在动态THML语句中调用JS函数传递带空格参数的问题

如何在 Javascript 中调用动态命名的方法?