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

The idea of the singleton pattern is that a class can return a reference to an object (and always be the same) and a method (a static method, usually using the getInstance name) to get that instance. So when we call this method, we return the reference that the class holds if it is not empty, otherwise we create an instance of the class, assign the instance reference to the reference that the class holds and return it. The constructor of the class is also defined as a private method, so that other functions can not use the constructor to instantiate the object, and only the static method of the class can get the unique instance of the class.

Application scenarios

In daily development, we often need to create a translucent mask layer for popovers. To reduce unnecessary DOM manipulation, the correct way to think about it is to determine whether the Model DIV has been generated before and not to generate it again.

Implementation steps

Step 1 Write a method that generates a Model div

   <style>
    .modal {
      position: fixed;
      left: 0;
      top: 0;
      width: 100%;
      height: 100%;
      opacity:.5;
      background: # 000;
      z-index: 99;
    }
  </style>
  
 <script>
  function createModal () {
    const div = document.createElement('div');
    div.className = 'modal';
    document.body.appendChild(div);
  }

  createModal()  
  createModal()  // Calling it twice produces two modal boxes
</script>  

Copy the code

Calling the createModal method twice will result in appending two divs to the body, which is obviously not what we want, and we need to add a variable to determine if it has already been called

Implement according to the definition of singleton pattern

  1. Ensure that there is only one instance of a classnew createModal()
  2. And provide a global access point to access itcreateModal.getInstanceMethods to access
  function createModal () {
    const div = document.createElement('div');
    div.className = 'modal';
    document.body.appendChild(div);
  }

  createModal.getInstance = function () {
    if (this.instace) {
      return this.instace;
    } else {
      this.instace = new createModal(); 
      return this.instace; }};const a = createModal.getInstance()
  const b = createModal.getInstance() // Call two instances once
  console.log(a === b)  // true
Copy the code

This section of code according to the singleton pattern definition to use JS to implement a singleton pattern, call many times will only instance a createModal, generate a modal box

Inert singleton

Due to the nature of JS, a private variable can be protected in the form of a closure that serves as a judgment value, and lazy functions represent object instances that are created when needed, not when the page loads

  const createModal = (function(){
    let div;
    return function(){
      if(! div){ div =document.createElement('div');
        div.className = 'modal';
        document.body.appendChild(div); }}}) (); createModal() createModal()// Call div twice to generate div once

Copy the code

With closures, div variables are protected and judged at call time

General pattern

If we need to create another div, we can only copy the code. Can we find a way to separate the div method from the return method?

  1. To create agetSinglemethodsresultIs the judgment variable
  2. To create acreateModalMethod to execute the code and return a bool togetSingleIn theresultjudge
  const getSingle = function (fn) {
    let result;
    return function () {
      return result || (result = fn.apply(this.arguments)); }};const createModal = function () {
    const div = document.createElement('div');
    div.className = 'modal';
    document.body.appendChild(div);
    return div
  }
  const createSingleDiv = getSingle(createModal)
  const a = createSingleDiv()
  const b = createSingleDiv()
  console.log(a === b)  // true
Copy the code

This creates a general pattern for creating lazy singletons

conclusion

Singleton pattern is widely used in practical development, especially in framework design. Rational use can improve performance.