【问题标题】:Javascript Revealing Module pattern - exposing initialization variables after function has returnedJavascript 显示模块模式 - 在函数返回后公开初始化变量
【发布时间】:2012-10-26 03:08:57
【问题描述】:

我一直在使用 Javascript 显示模块模式,我喜欢它在公共接口和内部之间提供的清晰分离。然而,我不断遇到一种情况,这让我怀疑我的整体使用模式是否正确,或者我是否应该使用该模式的一些变体。

问题在于,当传递给模块的 init 函数并私下存储以供内部使用的内容时,也需要在 Knockout 绑定表达式或其他模块中公开公开。模块的返回语句会立即执行,稍后会调用 init 函数,通常会传递一些动态参数,例如在 Razor 视图中的脚本块中呈现的 Ajax URL 或原始 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();

我的解决方法只是将诸如“url”之类的对象包装在一个函数中,然后通过 productsModule.getUrls() 访问它们。然而,这变得非常混乱,特别是如果变量是一个 Knockout observable,它本身就是一个函数,因此要评估它,我需要使用像 productsModule.getMyObservable()() 这样的双括号。

有没有更好的方法来使用至少接近揭示模块模式的东西来获取最新的内部值?

【问题讨论】:

    标签: javascript knockout.js revealing-module-pattern


    【解决方案1】:

    基本类型通过值传递,对象通过引用传递;您可以利用这一点,而不是在productsModule 中覆盖urls,您只需更新它。这样,在初始模块调用中返回的引用保持最新。我已更新您的代码以说明我的意思。

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

    【讨论】:

    • 对象是通过引用传递的,难道都是通过值传递的,但是对象的值是引用?跨度>
    • Aww,现在你让我头疼了 ;) 我不确定这实际上是在说什么不同。
    • 如果它是一个引用,你会期望this jsfiddle 输出"not a value" 吗?我不是 100% 肯定,但我相信有人会突然出现并给出明确的答案。
    • 这个问题在这一点上非常好:stackoverflow.com/questions/518000/…“传入的项是按值传递的。但是按值传递的项本身就是一个引用。”
    • 谢谢@TomHall。这种行为很常见; PHP 做的完全一样(但有第三个选项显式地通过引用传递,这将解决这个问题)。它通常被描述为通过引用传递对象,但显然这也不完全正确; php.net/manual/en/language.oop5.references.php.
    【解决方案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/
    

    【讨论】:

    • 如果你只打算传递简单的对象,那么合并的开销是最小的,但这似乎更好。
    • 厚颜无耻地接受自己的回答,但感谢您为我指明了正确的方向。
    • @TomHall:接受你自己的答案很好。在答案中写一个问题不是。
    【解决方案3】:

    为什么不让 urls 成为可观察的属性?

    看我的例子:

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

    您好。

    【讨论】:

    • 在 Knockout.js 世界中,这对于某些属性来说可能是一个合理的选择,尽管它看起来有点像不必要的开销(订阅)和括号,只是为了绕过 RMP 的尴尬流程。通常我的模块会暴露一个我不想观察到的沉重的顶层视图模型,只暴露它的属性和它的子视图模型的属性。不过还是不错的想法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-07-21
    • 2011-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-29
    • 1970-01-01
    相关资源
    最近更新 更多