Динамически вызывать локальную функцию в 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;
}