Динамически вызывать локальную функцию в javascript

есть много похожих вопросов о вызове функций по имени динамически. Однако я не могу найти решение моей конкретной проблемы, где у меня есть локальные функции внутри замыкания, не подвергая функции публичному интерфейсу моего объекта.

Давайте посмотрим на некоторый код (это вымышленный пример)...

(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

Вы не можете получить ссылку на локальную переменную с помощью строки. Вы должны добавить локальные объекты в пространство имен:

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

Ответ 2

Частные функции - это локальные переменные, а не часть любого объекта. Таким образом, нотация [...] для доступа к свойству никогда не будет работать, поскольку нет объектов, частными функциями которых являются свойства.

Вместо этого вы можете создать два объекта: private и 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

Ответ 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 было необходимо.

Ответ 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;
}