我一直在使用Javascript Revealing Module模式,我喜欢它在公共接口和内部之间的明确分离。但是我一直遇到一种情况,这让我想知道我的整体使用模式是否正确,或者我是否应该使用该模式的某些变体。
问题在于,当某些内容传递到模块的init函数并私有存储以供内部使用时,也需要公开公开,无论是在Knockout绑定表达式还是其他模块中。模块的return语句立即执行,稍后调用init函数,通常会传递一些动态参数,如Ajax URL或Razor视图中脚本块中呈现的原始JSON。因为模块的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 observable本身就是一个函数,因此要评估它我需要使用像productModule.getMyObservable()()这样的双括号。
是否有更好的方法可以使用至少接近显示模块模式的内容来获取最新的内部值?
答案 0 :(得分:2)
基本类型按值传递,而对象通过引用传递;您可以利用这一点,而不是覆盖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();
答案 1 :(得分:2)
虽然我不完全喜欢必须迭代我的对象的所有可能级别来合并它们的想法,但是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/
答案 2 :(得分:1)
为什么不将网址设为可观察的属性?
看看我的例子:
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();
问候。