【问题标题】:dynamically call local function in javascript在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
};

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

【问题讨论】:

    标签: javascript closures scope


    【解决方案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;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-07-06
        • 1970-01-01
        • 2014-01-31
        • 2014-10-24
        • 2010-10-08
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多