最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

closures - dynamically call local function in javascript - Stack Overflow

programmeradmin2浏览0评论

there are plenty of similar questions out there about calling functions by name dynamically. However, I can't find a solution to my specific problem where I have local functions inside a closure without exposing the functions to the public interface of my object.

Lets see some code (this is a fictional example)...

(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 doesn't work because "this" is MyObject and the local functions are not exposed. Also I'd like to be able to check if the function exists before trying to call it. eg.

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

I'm not really sure how to proceed, short of exposing my private functions to the public interface, it all works then.

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

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

I'm running out of ideas. Your help and advise is greatly appreciated.

there are plenty of similar questions out there about calling functions by name dynamically. However, I can't find a solution to my specific problem where I have local functions inside a closure without exposing the functions to the public interface of my object.

Lets see some code (this is a fictional example)...

(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 doesn't work because "this" is MyObject and the local functions are not exposed. Also I'd like to be able to check if the function exists before trying to call it. eg.

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

I'm not really sure how to proceed, short of exposing my private functions to the public interface, it all works then.

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

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

I'm running out of ideas. Your help and advise is greatly appreciated.

Share Improve this question edited May 2, 2012 at 18:38 user229044 239k41 gold badges344 silver badges346 bronze badges asked Feb 27, 2012 at 12:20 RobRob 7,0994 gold badges46 silver badges77 bronze badges
Add a comment  | 

5 Answers 5

Reset to default 8

The private functions are local variables and not part of any object. So, the [...] notation for accessing a property is never going to work since there is no object the private functions are properties of.

Instead, you could make two objects: private and public:

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

You cannot get a reference to a local variable by a string. You have to add the local objects to a namespace:

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

I'm surprised that incorrect answer is marked as accepted. Actually you CAN get a reference to a local variable by a string. Just by using 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);

Actually this code is very bad and in 99.9% cases you should not use eval. But you must know how it works and what you can do with it. I myself had a few very specific cases when usage of eval was necessary.

The fact that you cannot call these functions from outside of the scope within which they are defined is a fundamental part of javascript, and indeed, all programming languages.

The only way to call these functions is to make them public. A convention based approach can be applied instead however. The underscore prefix is fairly ubiquitous and generally understood to mean "not intended to be called as a public function" eg:

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

Assuming you only have a couple of functions to call, you can create your own version of Window to use to call the functions:

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

Then in your code:

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

Just make sure the functions are defined when you add them to the object. In a module where the functions don't exist at load time, you can add them when the module is initialized:

var myFuncs = {};
var init = function(){
    myFuncs['foo'] = foo;
    myFuncs['bar'] = bar;
}
发布评论

评论列表(0)

  1. 暂无评论