Шаблон модуля Javascript Revealing - отображение переменных инициализации после возврата функции
Я очень часто использую шаблон Javascript Revealing Module, и мне нравится четкое разделение, которое он дает между открытым интерфейсом и внутренними компонентами. Однако я продолжаю сталкиваться с ситуацией, которая заставляет меня задаться вопросом, является ли мой общий шаблон использования правильным, или мне следует использовать какой-то вариант шаблона.
Проблема заключается в том, что когда что-то передается в функцию init модуля и хранится в частном порядке для внутреннего использования, также должно быть открыто опубликовано, либо в выражении привязки Knockout, либо в каком-либо другом модуле. Оператор return модуля выполняется немедленно, а спустя некоторое время вызывается функция init, обычно передавая некоторые динамические параметры, такие как URL-адреса Ajax или необработанный JSON, представленные в блоке сценария в представлении Razor. Поскольку оператор return модуля просто возвращает копию закрытой переменной, а не ссылку, моя установка этой закрытой переменной в функции init не может изменить то, что уже было возвращено.
var productsModule = function() {
var urls;
var init = function(ajaxUrls) {
urls = ajaxUrls;
};
return {
init: init,
urls: urls,
getUrls: function() { return urls; }
};
}();
var customersModule = function() {
var doSomethingWithProductsModule = function() {
alert(productsModule.urls); // undefined
alert(productsModule.getUrls()); // object
} ;
return {
doSomethingWithProductsModule: doSomethingWithProductsModule
};
}();
var urls = {
getProduct: '/Product/'
};
productsModule.init(urls);
customersModule.doSomethingWithProductsModule();
Мой обходной путь - просто обернуть объекты, такие как "urls", в функцию, а затем получить к ним доступ через productsModule.getUrls(). Однако это становится очень грязным, особенно если переменная является наблюдаемой Knockout, которая сама является функцией, и, следовательно, для ее оценки мне нужно использовать двойные скобки, например productsModule.getMyObservable()().
Есть ли более хороший способ получить современные внутренние значения, используя что-то, что, по крайней мере, приближает образец модуля к раскрытию?
3 ответа
Хотя мне не совсем нравится идея перебора всех возможных уровней моих объектов для их слияния таким образом, ответ El Yobo заставил меня задуматься о том, чтобы сделать сам результат функции модуля локальной переменной, свойства которой я мог бы обновить,
var productsModule = function() {
var urls;
var init = function(ajaxUrls) {
urls = ajaxUrls;
result.urls = urls;
};
var result = {
init: init,
urls: urls
};
return result;
}();
// Before init
alert(productsModule.urls); // undefined
var urls = {
getProduct: '/Product/'
};
productsModule.init(urls);
alert(productsModule.urls.getProduct); // /Product/
Основные типы передаются по значению, а объекты передаются по ссылке; Вы можете использовать это так, чтобы вместо перезаписи urls
в productsModule
Вы просто обновляете это. Таким образом, ссылка, возвращенная при первоначальном вызове модуля, остается актуальной. Я обновил ваш код, чтобы показать, что я имею в виду.
var productsModule = function() {
var urls = {};
var init = function(ajaxUrls) {
// Merge properties into the original object instead; more robust approach
// may be needed
for ( name in ajaxUrls ) {
if (ajaxUrls.hasOwnProperty(name)) {
urls[name] = ajaxUrls[name];
}
}
};
return {
init: init,
urls: urls,
getUrls: function() { return urls; }
};
}();
var customersModule = function() {
var doSomethingWithProductsModule = function() {
alert(productsModule.urls); // undefined
alert(productsModule.getUrls()); // object
} ;
return {
doSomethingWithProductsModule: doSomethingWithProductsModule
};
}();
var urls = {
getProduct: '/Product/'
};
productsModule.init(urls);
customersModule.doSomethingWithProductsModule();
Почему бы вам не сделать URL-адрес заметным свойством?
Посмотрите на мой пример:
http://jsfiddle.net/Razaz/zkXYC/1/
var productsModule = function() {
var urls=ko.observable();
var init = function(ajaxUrls) {
urls(ajaxUrls);
};
return {
init: init,
urls: urls,
getUrls: function() { return urls(); }
};
}();
var customersModule = function() {
var doSomethingWithProductsModule = function() {
alert(productsModule.urls()); // undefined
alert(productsModule.getUrls()); // object
};
return {
doSomethingWithProductsModule: doSomethingWithProductsModule
};
}();
var urls = {
getProduct: '/Product/'
};
productsModule.init(urls);
customersModule.doSomethingWithProductsModule();
Привет.