knockout.js - Javascript Revealing Module pattern - exposing initialization variables after function has returned - Stack Overfl

I’ve been using the Javascript Revealing Module pattern a lot and I like the clear separation it gives

I’ve been using the Javascript Revealing Module pattern a lot and I like the clear separation it gives between the public interface and the internals. However I keep running into a situation which makes me wonder if my overall usage pattern is correct, or if I should use some variant of the pattern.

The problem is when something passed into the init function of a module and stored privately for internal use also needs to be publicly exposed, either in a Knockout binding expression or some other module. The return statement of the module executes immediately and sometime later the init function is called, typically being passed some dynamic parameters such as Ajax URLs or raw JSON rendered in a script block within a Razor view. Because the module's return statement just returns a copy of the private variable rather than a reference, my setting that private variable in the init function can’t change what has already been returned.

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

My workaround is just to wrap objects such as “urls” in a function and then access them via productsModule.getUrls(). However that bees very messy, especially if the variable is a Knockout observable which is itself a function, and hence to evaluate it I need to use double brackets like productsModule.getMyObservable()().

Is there a nicer way to get at the up-to-date internal values using something which at least approximates the revealing module pattern?

I’ve been using the Javascript Revealing Module pattern a lot and I like the clear separation it gives between the public interface and the internals. However I keep running into a situation which makes me wonder if my overall usage pattern is correct, or if I should use some variant of the pattern.

The problem is when something passed into the init function of a module and stored privately for internal use also needs to be publicly exposed, either in a Knockout binding expression or some other module. The return statement of the module executes immediately and sometime later the init function is called, typically being passed some dynamic parameters such as Ajax URLs or raw JSON rendered in a script block within a Razor view. Because the module's return statement just returns a copy of the private variable rather than a reference, my setting that private variable in the init function can’t change what has already been returned.

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

My workaround is just to wrap objects such as “urls” in a function and then access them via productsModule.getUrls(). However that bees very messy, especially if the variable is a Knockout observable which is itself a function, and hence to evaluate it I need to use double brackets like productsModule.getMyObservable()().

Is there a nicer way to get at the up-to-date internal values using something which at least approximates the revealing module pattern?

Share Improve this question edited Nov 22, 2022 at 2:13 Don't Panic 14.5k5 gold badges35 silver badges53 bronze badges asked Oct 26, 2012 at 3:08 Tom W HallTom W Hall 5,2834 gold badges31 silver badges35 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 2

Basic types are passed by value while objects are passed by reference; you could exploit this so that instead over overwriting urls in productsModule you just update it. This way the reference returned in the initial module invocation remains up to date. I've updated your code to show what I mean.

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

Although I don't pletely like the idea of having to iterate through all the possible levels of my objects to merge them like that, El Yobo's answer got me thinking about making the result of the module function itself a local variable whose properties I could update.

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/

Why don't you make urls an observable property ?

Look at my example:

http://jsfiddle/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();​

Greetings.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745303811a4621595.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信