单例模式与Javascript中的全局变量用例?

时间:2016-05-13 13:51:32

标签: javascript design-patterns singleton global-variables

背景

我正在自学编程(目前专注于JS)并且难以概念化Singleton设计模式。 (https://en.wikipedia.org/wiki/Singleton_pattern)介绍说明:

“[S] ome批评单身模式[考虑将其引入]应用程序中的全局状态。” (第1段)。“

文章正文指出: “单身人士往往更喜欢全球变量,因为: 它们不会使用不必要的变量污染全局命名空间(或者,在具有命名空间的语言中,包含其命名空间)。“

一起考虑,这些陈述混淆了我对单身人士是什么以及什么时候应该用来取代全球变量的理解。

问题/提问

是否有人可以共享一个可以在JS中使用Singleton或Global Variable实现的示例场景,并提供每个策略何时合适的用例?类比和隐喻以及代码是非常有用的!

1 个答案:

答案 0 :(得分:5)

命名空间

考虑像这样的index.html:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>Namespace</title>
</head>

<body>
    <div id="output">&nbsp;</div>

    <script src="scriptONE.js"></script>
    <script src="scriptTWO.js"></script>

    <script>
        print();
    </script>
</body>

</html>

scriptONE.js持有的地方

var output = "ONE";

var print = function() {
    var div = document.getElementById("output");
    div.innerHTML = output;
}

scriptTWO.js包含

var output = "TWO";

var print = function() {
    var div = document.getElementById("output");
    div.innerHTML = output;
}

......运行这个,会发生什么?是的,该网站将显示 TWO 。因为这两个脚本基本上都在污染全局命名空间,因此会发生冲突。 ScriptONE的print被scriptTWO的同名函数所取代。

如果我们编辑像这样的scriptTWO.js,问题仍然存在

var output = "TWO";

var printTWO = function() {
    var div = document.getElementById("output");
    div.innerHTML = output;
}

...因为?对! output仍然围绕@global进行民意调查。当print()被称为var output时,已被覆盖。

现在,我们可以包含我们自己的脚本(scriptTWO),而不是检查我们在某处清除的每个脚本(scriptONE)并避免将它放入全局命名空间的每个变量名称。

// obviously our countainer should not be named "print"
var myPrintDemo = {};

(function PRINTMODULE(api) {
    var output = "TWO";

    api.print = function () {
        var div = document.getElementById("output");
        div.innerHTML = output;
    }
}(myPrintDemo));

我们的index.html现在显示: ONE ,我们可以使用新的print()替换myPrintDemo.print(),以使页面显示 TWO 。< / p>

......但为什么呢?发生了什么?我们在那里做的伏都教是什么?

我们创建了对象myPrintDemo。接下来我们'立即调用'函数PRINTMODULE。只要您遇到类似(function () { ... }());的内容,就可以完成此操作。该函数立即调用;因此模式的名称:立即调用的函数表达式。

我们使用了这个模式并将它作为我们的对象(通过将它放入最后一对())。我们告诉我们的函数在内部引用它为api。现在,前面没有api.的所有内容基本上都是一个私有变量,只能在PRINTMODULE函数的范围内看到。然而,我们使用api.“前缀”的所有内容都可以作为对象myPrintDemo的属性之一进行访问。

这个模块模式很方便(,伏都教)而且非常重要,你一定要多检查一下。某个地方比我更有能力。也许一本书?我很喜欢Douglas Crockford的“Javascript The Good Parts”。哎呀,这让我理解scope!我实际买了它,但也可以在这里阅读:http://bdcampbell.net/javascript/book/javascript_the_good_parts.pdf

  

学习JScript,你可以更加依赖Crockford,使用   http://jslint.com/

     

意见可能有所不同,但为自己说话:   没有什么比教我一起教我更多的东西......然后   让它通过jslint!

的Singleton?

好的。因此,使用单个对象来包含我们所有的东西都有其优点。它“将全局状态引入应用程序”这一点显然没有实际意义,因为JScript带有全局性。

但这个模块设计模式真的是单身吗?罗。我们试图将自己包含在全局命名空间中的单个对象中。但是单身实际上需要这个特征必然是唯一的。

var Singleton = (function () {
    var instance;

    function createInstance() {
        var that = {};

        // define our module here

        return that;
    }

    // now this is the part that makes it a singleton:
    return {
        get: function () {
            if (!instance) {
                // only create an instance if there is none!
                instance = createInstance();
            }
            // always return the same object!
            return instance;
        }
    };
})();

正如您所注意到的:这是用我们的内容填充对象的一种稍微不同的方式。我们不是首先声明Singleton一个对象然后将它提供给一个iffy(立即调用的函数表达式),而是直接声明它是一个iffy的结果。

您可以使用任何一种方式。这种差异并不是使这种模式产生更多真正的单身人士的原因。这是JScript对Singleton的实现,因为检查createInstance()内是否已存在任何内容的实例。

(我使用第一种方式明显而方便地使用api.来公开)。