Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 这个JS单例模式如何/为什么工作?_Javascript_Constructor_Singleton_This - Fatal编程技术网

Javascript 这个JS单例模式如何/为什么工作?

Javascript 这个JS单例模式如何/为什么工作?,javascript,constructor,singleton,this,Javascript,Constructor,Singleton,This,我遇到了一种非常有趣的方法来创建一个JavaScript单例,它可以用new关键字实例化,比如var x=new SingletonClass()。我对变量作用域和闭包等有很好的理解,但是我很难准确地理解为什么这段代码是这样工作的 // EDIT: DO NOT USE this code; see the answers below function SingletonClass() { this.instance = null; var things = []; functio

我遇到了一种非常有趣的方法来创建一个JavaScript单例,它可以用
new
关键字实例化,比如
var x=new SingletonClass()
。我对变量作用域和闭包等有很好的理解,但是我很难准确地理解为什么这段代码是这样工作的

// EDIT: DO NOT USE this code; see the answers below
function SingletonClass() {
  this.instance = null;
  var things = [];

  function getInstance() {
    if (!this.instance) {
      this.instance = {
        add: function(thing) {
          things.push(thing);
        },
        list: function() {
          console.log(things.toString());
        }
      };
    }
    return this.instance;
  }

  return getInstance();
}

var obj1 = new SingletonClass();
obj1.add("apple");
obj1.list();  //"apple"

var obj2 = new SingletonClass();
obj2.add("banana");
obj1.list();  //"apple,banana"
obj2.list();  //"apple,banana"

obj1.add("carrot");
obj1.list();  //"apple,banana,carrot"
obj2.list();  //"apple,banana,carrot"
我的直觉告诉我,每次实例化一个新的
SingletonClass
this
引用那个新的对象——但是由于构造函数返回一个完全独立的对象,我认为
this
会被丢弃。但它仍然存在。怎么用?为什么?

这里有一些我不知道的小细节。有人能照点光吗


编辑:结果显示此代码不正确。它之所以“神奇地”保存对实例的引用,是因为它实际上在全局对象中静默地存储它。充其量这是一种不好的做法,毫无疑问容易出现错误。

当构造函数调用
getInstance()
时,
getInstance()
中的
this
指针被设置为
window
,因此
this.instance
内部是一个全局变量
window.instance

这段代码只使用了一个全局变量
window.instance
来跟踪一个实例,可以使它变得更简单

一个更干净的实现方法是这样。一个全局实例存储为函数本身的属性,而不是存储在顶级全局变量中

    function SingletonClass() {
        var things = [];

        // if there is a previous instance, return it
        if (SingletonClass.inst) {
            return SingletonClass.inst;
        }
        // if not called with 'new', force it
        if (!this instanceof SingletonClass) {
            return new SingletonClass();
        }

        // remember the first created instance
        SingletonClass.inst = this;

        // add methods that can see our private `things` variable
        this.add = function(thing) {
           things.push(thing);
        }

        this.list = function() {
            console.log(things.toString());
        }
    }

它使用的是
窗口
-
getInstance
单例类
的以下内容不同:

function Singleton() {
    console.log("This is:", this);
    this.instance = null;

    function _get() {
        console.log("_get's this is:", this);
        if (!this.instance) {
           console.log("Instance is null");
           this.instance = { test: 1 };
        }
        return this.instance;
    }

    return _get();
}

var x = new Singleton();

// Output is:
This is: 
Singleton
_get's this is: 
Window
Instance is null
在JavaScript中实现单例模式的更好方法可能是:

function Singleton() {

    // Handle not being called with `new`
    if (!this instanceof Singleton) {
        return new Singleton();
    }

    var instantiating = !!Singleton.instance,
        things = [];

    Singleton.instance = instantiating ? this : Singleton.instance;

    if (instantiating) {
        this.list = function() {
            console.log(things.toString());
        }

        this.add = function(item) {
            things.push(item);
        }
    }

    return Singleton.instance;
}
这仍然受到限制。例如,如果有人用另一个对象替换了
Singleton.instance
,那么
Singleton
的不同实例之间的测试可能会中断-例如:

var x = new Singleton();
// Har, har, we be breaking things!
Singleton.instance = {"not": "the", "same": "at", "all": true};
var y = new Singleton();

console.log(x === y); // false

不要被函数
getInstance
中的
this
所迷惑,
this
是全局对象
window
,因此您正在创建一个对象并分配给window对象,下次调用构造函数时,您将检查
window.instance
是否存在

代码
this.instance=null毫无意义,只是让你困惑。移除它不会改变任何事情

下面是来自

当执行代码
newfoo(…)
时,会发生以下情况:

  • 将创建一个从foo.prototype继承的新对象
  • 使用指定的参数调用构造函数foo 这将绑定到新创建的对象。新的foo相当于
    new foo()
    ,即如果未指定参数列表,则调用foo 没有争论
  • 构造函数返回的对象成为结果 整个新表达式的属性。如果构造函数没有 显式返回一个对象,使用在步骤1中创建的对象 相反(通常构造函数不返回值,但它们可以 如果要覆盖普通对象创建,请选择这样做 过程。)

  • 注意步骤3,当构造函数中有return语句时,返回的结果将是新表达式的结果。

    函数中的关键字
    this
    表示一个
    窗口
    对象。在
    SingletonClass
    函数中,它表示
    SingletonClass
    对象


    对于词法范围,
    add
    list
    函数总是引用相同的
    事物
    数组。

    这似乎是关于单例的一个很好的链接:

    下面是一个与您在上面所做工作相关的示例:

    var myInstance = {
        method1: function () {
            return "Apple";
        },
        method2: function () {
            return "Orange";
        },
        banana: "Banana"
    };
    
    myInstance.grape = "Grape";
    
    console.log(myInstance.method1(), myInstance.method2(), myInstance.banana, myInstance.grape);
    
    以下是工作链接:


    你在哪里找到的?我觉得它坏了。“getInstance”函数是在没有显式接收器的情况下调用的,因此
    this
    将是全局对象(
    浏览器中的窗口
    )。请注意,如果在严格模式下调用,
    getInstance
    中的
    this
    将未定义,引发引用错误(或类似错误)正在尝试评估这个实例。你是对的@Pointy,我现在意识到它(概念上)被破坏了。我从来没有想过,
    这个
    可以指的是全局对象。是的,我现在明白了。我想当然地认为,
    这个
    总是意味着,
    这个
    ,我甚至从未想过检查全局对象。我会用一个大的“请勿使用”注释来修改代码,以防有人想出复制它的好主意。;)很遗憾,我只能接受一个答案,因为我也喜欢这个答案(尤其是替换代码)。最初吸引我关注我发布的代码的是,它声称这样做没有向类中添加属性——但事实证明它是snake oil,而是存储在
    窗口中。