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

sam*_*chl 4 javascript singleton design-patterns global-variables

背景

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

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

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

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

问题/问题

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

Jon*_*ter 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>
Run Code Online (Sandbox Code Playgroud)

scriptONE.js所在的位置

var output = "ONE";

var print = function() {
    var div = document.getElementById("output");
    div.innerHTML = output;
}
Run Code Online (Sandbox Code Playgroud)

并且scriptTWO.js包含

var output = "TWO";

var print = function() {
    var div = document.getElementById("output");
    div.innerHTML = output;
}
Run Code Online (Sandbox Code Playgroud)

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

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

var output = "TWO";

var printTWO = function() {
    var div = document.getElementById("output");
    div.innerHTML = output;
}
Run Code Online (Sandbox Code Playgroud)

......因为?对!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));
Run Code Online (Sandbox Code Playgroud)

我们的index.html现在显示:ONE,我们可以print()用新的替换myPrintDemo.print()来使页面显示为TWO.

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

我们创建了这个对象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

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

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

辛格尔顿?

行.因此,使用单个对象来包含我们所有的东西都有其优点.它"将全局状态引入应用程序"这一点显然没有实际意义,因为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;
        }
    };
})();
Run Code Online (Sandbox Code Playgroud)

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

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

(我正在使用第一种方式,明显但方便地使用api.公开的东西).