带有闭包解释的Javascript Singleton

Javascript Singleton with Closure explanation

本文关键字:Javascript Singleton 解释 闭包      更新时间:2023-09-26

简介:我开始读Javascript Patterns一书,但一个例子都抓不住。它相当大,所以在给你一个代码之前,我会试着简单地解释一下。

示例解释:所以他们试图在闭包的帮助下定义singleton。第一段代码非常简单,但它有一个显著的缺点——我们不能在创建第一个Universe实例后重新定义原型。

问题: 有人能解释一下第二个示例("Good"singleton)代码是如何在第一次构造函数调用后更改原型的吗

"坏"单例:

function Universe() {
    var instance = this;
    this.start_time = 0; 
    this.bang = "Big";
    Universe = function () {
        return instance; 
    };
}
// testing
Universe.prototype.nothing = true;
var uni = new Universe();
Universe.prototype.everything = true;
var uni2 = new Universe();
uni.nothing; // true 
uni2.nothing; // true 
//AS YOU CAN SEE ALL CHANGES TO UNIVERSE PROTOTYPE HAVE NO RESULT AFTER FIRST CONSTRUCTOR CALL
uni.everything; // undefined 
uni2.everything; // undefined

然后他们用下面的代码解决了问题:

"良好"单例:

function Universe() {
    var instance;
    Universe = function Universe() {
       return instance; 
    };
    Universe.prototype = this;
    instance = new Universe();
    instance.constructor = Universe;
    instance.start_time = 0; 
    instance.bang = "Big";
    return instance; 
}
// testing
Universe.prototype.nothing = true;
var uni = new Universe();
//QUESTION: how does it manage to change the prototype of singleton?!
Universe.prototype.everything = true;
var uni2 = new Universe();
uni.nothing && uni.everything && uni2.nothing && uni2.everything; // true

换句话说,同样的问题是:为什么在第一个代码片段uni.everything == falseuni2.everything == false中,而在第二个代码片段中是uni.everything == trueuni2.everything == true?就我而言,在这两种情况下,它们都应该是false

注意:请随意改写这个答案,使其听起来更好,我可能没有很好地解释。

示例1("坏"单例)

在你的第一个例子中:

function Universe() {
    var instance = this;
    this.start_time = 0; 
    this.bang = "Big";
    Universe = function () {
        return instance; 
    };
}

当您第二次调用new Universe()时,它会返回第一次存储的instance(当全局Universe构造函数被替换时),而不是新对象。这就是为什么对Universe.prototype的任何更改都没有效果。

示例2("良好"单例)

你的第二个例子有点复杂。第一次调用它时,this指的是最初创建的对象,这意味着它具有具有nothing属性的原型。由于该对象现在是返回实例的原型,因此继承了nothing属性。

因为现在,当您第二次调用new Universe()时,它会返回第一次调用的instance = new Universe()的结果,对它的任何更改也会随之保留。

因为您在原始Universe函数中返回了instance,所以uniuni2是同一个对象。

这将具有与这样做相同的效果:

var Universe2;
function Universe() {
    Universe2 = function () {
         return instance; 
    };
    Universe2.prototype = this;
    var instance = new Universe2();
    instance.constructor = Universe2;
    instance.start_time = 0; 
    instance.bang = "Big";
    return instance;
}
Universe.prototype.nothing = true;
var uni = new Universe();
Universe2.prototype.everything = true;
var uni2 = new Universe2();

最后一个物体看起来是这样的:

==========================
= Object.prototype       =
=  - hasOwnProperty: ... =
=  - toString: ...       =
=  - ...                 =
==========================
            ^
            |
            |
            |
            |
==========================
= Universe.prototype:    =
=   - nothing: true      =
==========================
            ^
            |
            |
            |
            |
==========================
= Instance of Universe:  =
=  - everything: true    =
==========================
            ^
            |
            |
            |
            |
==========================
= Instance of Universe2: =
=  - start_time: 0       =
=  - bang: "Big"         =
==========================