Singleton pattern: Limits class instantiation to one instance, one instance of a class, and provides a global access point to access it.

The singleton pattern is a type of creative design pattern. For scenarios where only one object is needed globally, such as thread pools, global caches, window objects, and so on.

Model features

  1. Class has only one instance
  2. The instance is globally accessible
  3. Self-instantiation (active instantiation)
  4. Deferred initialization, i.e., delayed execution (as opposed to static classes/objects)

JavaScript is an informal object-oriented language with no class definition. The singleton pattern, on the other hand, requires a “unique” and “globally accessible” object, which is similar to a global object in JavaScript and satisfies two characteristics of the singleton pattern: “unique” and “globally accessible.” Although it is not a regular singleton pattern, it does have the characteristics of a singleton pattern.

// Global objects
var globaObj = {};
Copy the code

Using global variables has the following problems:

  1. Namespace contamination (variable name conflicts)
  2. Inconvenient control during maintenance (easy to accidentally overwrite)

Compromise solutions to global variable problems:

  1. Using namespaces
  2. Closures encapsulate private variables (using function scope)
  3. ES6 const/symbol

Although global variables can realize singletons, due to its own problems, it is not recommended to be used as a singleton pattern in practical projects, especially in the application of medium and large projects, the maintenance of global variables should be considered as a cost.

Pattern implementation

Implementation: Use a variable to store the class instance object (initial value null/undefined). During class instantiation, the system checks whether the class instance object exists. If it does, the system returns the instance. If it does not, the system returns after creating the class instance. Call the class generation instance method multiple times to return the same instance object.

“Simple version” singleton pattern:

let Singleton = function(name) {
    this.name = name;
    this.instance = null;
}

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

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

let Winner = Singleton.getInstance('Winner');
let Looser = Singleton.getInstance('Looser');

console.log(Winner === Looser); // true
console.log(Winner.getName());  // 'Winner'
console.log(Looser.getName());  // 'Winner'
Copy the code

The code defines a Singleton function, which is a “first-class citizen” in JavaScript, for which you can define attribute methods. So instead of creating class instance objects through the traditional new operator, we can define a getInstance() method in the Singleton function to manage singletons and create objects that return class instances.

Each time getInstance() is called, the value of this.instance is returned, and the value of this.instance is created and updated, so no matter how many times getInstance() is called, All will eventually return the same Singleton class instance object.

Existing problems:

  1. Not “transparent” enough to be usednewTo instantiate the class, we need to restrict the call method of the class instantiation:Singleton.getInstance(...);
  2. The operation of managing singletons, coupled with the operation of object creation, function code, does not comply with the single responsibility principle

Transparent edition singleton pattern:

Use the new operator to get singletons instead of singleton.getInstance (…). .

let CreateSingleton = (function(){
    let instance;
    return function(name) {
        if (instance) {
            return instance;
        }
        this.name = name;
        return instance = this;
    }
})();
CreateSingleton.prototype.getName = function() {
    console.log(this.name);
}

let Winner = new CreateSingleton('Winner');
let Looser = new CreateSingleton('Looser');

console.log(Winner === Looser); // true
console.log(Winner.getName());  // 'Winner'
console.log(Looser.getName());  // 'Winner'
Copy the code

The “transparent” singleton solves the problem of not being transparent enough, and we can use the new operator to create instance objects again.

“Proxy edition” singleton pattern:

In the form of “agent”, the intention is to solve: the management singleton operation is separated from the object creation operation to achieve smaller granularity, in line with the “single responsibility principle”.

let ProxyCreateSingleton = (function(){
    let instance;
    return function(name) {
        // Proxy functions are used only as control singletons
        if (instance) {
            return instance;
        }
        return instance = new Singleton(name);
    }
})();

// A separate Singleton class that handles object instances
let Singleton = function(name) {
    this.name = name;
}
Singleton.prototype.getName = function() {
    console.log(this.name);
}

let Winner = new PeozyCreateSingleton('Winner');
let Looser = new PeozyCreateSingleton('Looser');

console.log(Winner === Looser); // true
console.log(Winner.getName());  // 'Winner'
console.log(Looser.getName());  // 'Winner'
Copy the code

Lazy singleton pattern

Lazy singleton, intended to resolve: class instance objects are created only when needed. For lazy load performance optimization, presumably front-end developers are no strangers. Lazy singletons also solve the “load on demand” problem.

Requirement: page pop-up prompt, multiple calls, only one popup object, but different display information content.

To develop such a global popover object, we can apply the singleton pattern. To improve its performance, we can have it generate instances and create DOM nodes only when we need to call it.

let getSingleton = function(fn) {
    var result;
    return function() {
        return result || (result = fn.apply(this.arguments)); // Determine this context and pass the parameters}}let createAlertMessage = function(html) {
    var div = document.createElement('div');
    div.innerHTML = html;
    div.style.display = 'none';
    document.body.appendChild(div);
    return div;
}

let createSingleAlertMessage = getSingleton(createAlertMessage);
document.body.addEventListener('click'.function(){
    // Multiple clicks will only produce a popover
    let alertMessage = createSingleAlertMessage('You need to pay for your knowledge! ');
    alertMessage.style.display = 'block';
})
Copy the code

GetSingleton (…) is used to create a generic “lazy singleton”. If you also need a createLoginLayer login box, createFrame Frame box, you can call getSingleton(…). Method to generate the corresponding instance object.

Applicable scenario

“Singleton pattern characteristics, intended to solve: maintain a global instance object.”

  1. References to third-party libraries (multiple references will only use one library reference, such as jQuery)
  2. Popup window (login box, information promotion box)
  3. Shopping cart (only one shopping cart per user)
  4. Global State Management Store (Vuex/Redux)

When a third party library is introduced in a project, only one library object will be instantiated globally when the library file is loaded repeatedly, such as jQuery, Lodash, moment… In fact, their implementation concept is also a kind of singleton pattern application:

// Introduce library libs
if (window.libs ! =null) {
  return window.libs;    // Return directly
} else {
  window.libs = '... ';   / / initialization
}
Copy the code

The advantages and disadvantages

  • Advantages: Applicable to a single object, only one object instance is generated, avoiding frequent creation and destruction of instances, reducing memory consumption.
  • Disadvantages: Not applicable to dynamically extending objects or scenarios where multiple similar objects need to be created.

TIPS: In multithreaded programming languages, singletons involve synchronization locks. JavaScript is a single-threaded programming language, so you can ignore this problem for now.


Refer to the article

  • JavaScript Design Patterns
  • JavaScript Design Patterns and Development Practices
  • Explanation and Application of JavaScript Design Pattern System

Github is looking forward to Star! Github.com/ZengLingYon…

Author: in the name of music this article is original, there are inappropriate places welcome to point out. Reprint please indicate the source.