简体   繁体   English

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

[英]Singleton pattern vs. Global variable use cases in Javascript?

Background 背景

I'm teaching myself programming (focused on JS at the moment) and having trouble conceptualizing Singleton design patterns. 我正在自学编程(目前专注于JS)并且难以概念化Singleton设计模式。 The ( https://en.wikipedia.org/wiki/Singleton_pattern ) introduction states: https://en.wikipedia.org/wiki/Singleton_pattern )介绍说明:

"[S]ome who are critical of the singleton pattern [consider it to introduce] global state into an application." “[S] ome批评单身模式[考虑将其引入]应用程序中的全局状态。” (1st paragraph)." (第1段)。“

The body of the article states: "Singletons are often preferred to global variables because: They do not pollute the global namespace (or, in languages with namespaces, their containing namespace) with unnecessary variables." 文章正文指出:“单身人士往往更喜欢全局变量,因为:他们不会用不必要的变量污染全局命名空间(或者,在具有命名空间的语言中,包含其名称空间)。”

Considered together, these statements muddle my understanding of what singletons are and when they should be used in place of global variables. 综合考虑,这些陈述混淆了我对单身人士是什么以及什么时候应该用来取代全球变量的理解。

The Question/Ask 问题/问题

Could anyone share an example scenario that could be implemented in JS with either a Singleton or Global Variable and provide a use case for when each strategy would be appropriate? 任何人都可以共享一个可以在JS中使用Singleton或Global Variable实现的示例场景,并提供每个策略何时合适的用例? Analogies and metaphors alongside code are extra helpful! 类比和隐喻以及代码是非常有用的!

Namespace 命名空间

Consider an index.html like this: 考虑像这样的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>

Where scriptONE.js holds scriptONE.js所在的位置

var output = "ONE";

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

And scriptTWO.js contains 并且scriptTWO.js包含

var output = "TWO";

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

... running this, what will happen? ......运行这个,会发生什么? Right, the website is gonna display TWO . 是的,该网站将显示两个 Because both scripts are basically polluting the global namespace and thus conflicts occur. 因为这两个脚本基本上都在污染全局命名空间,因此会发生冲突。 ScriptONE's print is replaced by scriptTWO's function of the same name. ScriptONE的print由scriptTWO的同名函数替换。

The problem remains if we edit scriptTWO.js like that 如果我们像这样编辑scriptTWO.js,问题依然存在

var output = "TWO";

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

... because? ......因为? Right! 对! output is still polloitering around @global. output仍然围绕@global进行开拓。 By the time print() is called var output already has been overwritten. print()被调用时, var output已被覆盖。

Now, instead of checking every script we scavenged somewhere (scriptONE) and avoid every variable name it puts out into the global namespace, we could contain our own script (scriptTWO). 现在,我们可以包含我们自己的脚本(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));

Our index.html now displays: ONE and we could replace print() with our new myPrintDemo.print() to make the page display TWO . 我们的index.html现在显示: ONE ,我们可以用新的myPrintDemo.print()替换print() ,使页面显示为TWO

...but why? ...但为什么? What happened? 发生了什么? What's that voodoo that we did there? 我们在那里做的伏都教是什么?

We created the object myPrintDemo . 我们创建了对象myPrintDemo Next we 'immediately invoked' the function PRINTMODULE. 接下来我们'立即调用'函数PRINTMODULE。 This is done whenever you encounter something like this (function () { ... }()); 每当遇到类似这样的事情时都会这样做(function () { ... }()); . The function is called immediately; 该函数立即调用; hence the pattern's name: Immediately-invoked function expression. 因此模式的名称:立即调用的函数表达式。

We used this pattern and fed it our object (by putting it into the last pair of () ). 我们使用了这个模式并将它作为我们的对象(通过将它放入最后一对() )。 We told our function to internally reference to it as api . 我们告诉我们的函数在内部引用它作为api And now everything without api. 现在一切都没有api. in front of it is basically a private variable, that's only visible within the scope of our PRINTMODULE function. 在它前面基本上是一个私有变量,它只在我们的PRINTMODULE函数范围内可见。 Yet everything we "prefix" with api. 然而,我们用api. “加上”前缀的一切api. is going to be accessible as one of object myPrintDemo 's attributes. 将作为对象myPrintDemo的属性之一进行访问。

This module pattern is that handy(, voodoo) and important, you should definitely check it out more & someplace more competent than me. 这个模块模式很方便(,伏都教)和重要的,你应该更多地检查它和某些比我更有能力的地方。 Maybe a book? 也许一本书? I enjoyed Douglas Crockford's "Javascript The Good Parts" a great deal. 我很喜欢Douglas Crockford的“Javascript The Good Parts”。 Heck, it made me understand scope ! 哎呀,这让我理解了scope I actually bought it, yet it can be read here, too: http://bdcampbell.net/javascript/book/javascript_the_good_parts.pdf 我实际买了它,但它也可以在这里阅读: http//bdcampbell.net/javascript/book/javascript_the_good_parts.pdf

Learning JScript you could rely even more on Crockford, using http://jslint.com/ . 使用http://jslint.com/学习JScript,你可以更多地依赖Crockford。

Opinions may differ, but speaking for myself: nothing taught me more than hacking something together ...and then making it pass jslint! 意见可能会有所不同,但为自己说话:没有什么比教我一起教我更多的东西......然后让它通过jslint!

Singleton? 辛格尔顿?

All right. 行。 So the use of a single object to contain all our stuff has its merits. 因此,使用单个对象来包含我们所有的东西都有其优点。 The point that it "introduces global state into an application" is obviously moot, because JScript comes with global. 它“将全局状态引入应用程序”这一点显然没有实际意义,因为JScript带有全局性。

But is this module design pattern truly a singleton? 但这个模块设计模式真的是单身吗? Nah. 罗。 We try to contain ourselves to a single object in the global namespace. 我们试图将自己包含在全局命名空间中的单个对象中。 But a singleton actually needs the feature to be necessarily unique. 但是单身实际上需要这个特征必然是唯一的。

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

As you notice: this is a slightly different way to fill our object with its content. 正如您所注意到的:这是用我们的内容填充对象的一种稍微不同的方式。 Instead of first declaring Singleton an object and then feeding it to an iffy (Immediately-invoked function expression), we directly declare it to be the result of an iffy. 我们不是首先声明Singleton一个对象然后将它提供给一个iffy(立即调用的函数表达式),而是直接将它声明为iffy的结果。

You can use either way. 你可以使用任何一种方式。 This difference is not what makes this pattern produce something more of a true Singleton. 这种差异并不是使这种模式产生更多真正的单身人士的原因。 This is JScript's implementation of a Singleton, because of the check if there already is an instance of whatever goes on inside createInstance() . 这是JScript对Singleton的实现,因为检查是否已经存在createInstance()内部的任何实例。

(I am using the first way for its obvious yet convenient use of api. to make things public). (我正在使用第一种方式来显而易见地使用api.来公开事物)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM