Design patterns are defined as simple and elegant solutions to specific problems in object-oriented software design. For JS, design patterns are a way of organizing properties and methods together

Singleton pattern: Ensure that a class has only one instance and provide a global access point to access it

Application of singleton pattern:

  • The thread pool
  • Global cache
  • The window object in the browser

The Singleton pattern can be implemented by adding a flag: add an instance attribute to the Singleton, set it to null initially, set instance to point to the instantiated object after the Singleton is instantiated, and return instance to ensure that a unique instance is obtained.

Add function attributes to implement the singleton pattern

function Singleton(name){
    this.name = name;
    this.instance = null;
}
Singleton.getInstance = function (name){
    if(!this.instance){
        this.instance = new Singleton(name)
    }
    return this.instance;
}

Singleton.prototype.getName = function(){
    return this.name;
}

/ / test
let a = Singleton.getInstance('John')
let b = Singleton.getInstance('Lili');
console.log(a);
console.log(b)
console.log(a === b)
Copy the code

This method, however, adds an instance attribute to the Singleton. If this attribute is not needed, it can be put into the scope of singleton.getInstance using self-executing anonymous functions and closures.

function Singleton(name){
    this.name = name;
}
// An immediate function that returns a closure function
Singleton.getInstance = (function (){
    let instance = null;
    return function (name){
        if(! instance){ instance =new Singleton(name)
        }
        return instance;
    }
})();

Singleton.prototype.getName = function(){
    return this.name;
}

/ / test
let a = Singleton.getInstance('John')
let b = Singleton.getInstance('Lili');
console.log(a);
console.log(b)
console.log(a === b)
Copy the code

The above two implementations are relatively simple, but they add to the class’s “opacity” as opposed to our usual new instantiation. The next step is to use new to wrap the Singleton function with an immediately executed anonymous function and closure.

We need to check whether we use the new form, because if we don’t use the new form, this will refer to window or undefined, and the program will report an error.

New form of singleton pattern implementation

const Singleton = (function(){
    / / logo
    let instance = null;
    // Returns an anonymous function
    return function(name){
        if(! instance){// Check whether the new method is used
            if(new.target ! = =undefined) {this.name = name;
                instance = this;
            }
            else{
                // If it is not new, an error is reported
                throw new Error('must use new')}}// Return the instance
        return instance;
    }
})();

/ / test
let a = new Singleton('John')
let b = new Singleton('Lili');
console.log(a);
console.log(b)
console.log(a === b)
Copy the code

The above implementation, in fact, is the class construction function and singleton function coupled together, increasing the complexity of the program, is not conducive to understanding. So you can separate the two functions. Introduce proxy classes to implement singleton functionality.

function Singleton(name){
    this.name = name;
}
const ProxySingleton = (function(){
    / / logo
    let instance = null;
    // Returns an anonymous function
    return function(name){
        if(! instance){// Check whether the new method is used
            if(new.target ! = =undefined){
                instance = new Singleton(name);
            }
            else{
                // If it is not new, an error is reported
                throw new Error('must use new')}}// Return the instance
        return instance;
    }
})();

/ / test
let a = new ProxySingleton('John')
let b = new ProxySingleton('Lili');
console.log(a);
console.log(b)
console.log(a === b)
Copy the code

ProxySingleton implements this. Name = name; this.name = name; instance = this; Instance = new Singleton(name); But the responsibilities are clearly delineated. ProxySingleton can also be passed in as a generic singleton function.