динамически вызывать локальную функцию в JavaScript - PullRequest
4 голосов
/ 27 февраля 2012

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

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

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

Я работаювне идей.Мы очень ценим вашу помощь и совет.

Ответы [ 5 ]

7 голосов
/ 27 февраля 2012

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

Вместо этого вы можете сделать два объекта: 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
6 голосов
/ 27 февраля 2012

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

(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 голосов
/ 16 января 2015

Я удивлен, что неправильный ответ помечен как принятый.На самом деле вы можете получить ссылку на локальную переменную по строке.Просто используя 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.

0 голосов
/ 15 июня 2019

Если у вас есть только пара функций для вызова, вы можете создать свою собственную версию Window для вызова функций:

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

Тогда в вашем коде:

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

Просто убедитесь, что функции определены, когда вы добавляете их к объекту. В модуле, где функции не существуют во время загрузки, вы можете добавить их при инициализации модуля:

var myFuncs = {};
var init = function(){
    myFuncs['foo'] = foo;
    myFuncs['bar'] = bar;
}
0 голосов
/ 27 февраля 2012

Тот факт, что вы не можете вызывать эти функции за пределами области, в которой они определены, является фундаментальной частью javascript, и, действительно, всех языков программирования.сделать их публичными.Однако вместо этого может быть применен подход, основанный на соглашениях.Префикс подчеркивания является вездесущим и обычно понимается как «не предназначен для вызова в качестве публичной функции», например:

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