JavaScript programming singleton design die explanation

  • 2020-10-23 20:00:48
  • OfStack

In Javascript, the singleton is one of the most basic and frequently used design patterns that may be inadvertently used.
This paper will start from the most basic theory, tell the basic concept and implementation of singleton pattern, and finally use an example to tell the application of singleton pattern.

Theoretical basis

concept

The singleton pattern, as the name implies, has only 1 instance. The singleton pattern ensures that there is only one instance of a class in the system and the instance is easy to be accessed by the outside world, thus facilitating the control of the number of instances and saving system resources. If you want to have only one object for a class in your system, singleton mode is the best solution.

The basic structure

The simplest singleton pattern starts with an object literal that organizes associated properties and methods into 1.


var singleton = {
  prop:"value",
  method:function(){
  }
}

This form of singleton pattern, where all members are public, is accessible via singleton. The disadvantage is that there are some auxiliary methods in the singleton that are not intended to be exposed to the user. If the user USES these methods and then maintains them later, some auxiliary methods are removed, which can cause program errors.
How can you avoid such mistakes?

A singleton pattern that contains private members

How do you create private members in a class? This is done by requiring closures, which I won't cover in this article, but Google.
The basic form is as follows:


var singleton = (function () {
      var privateVar = "private";
      return {
        prop: "value",
        method: function () {
          console.log(privateVar);
        }
      }
    })();

The first is a self-executing anonymous function, in which a variable privateVar is declared and an object is assigned to the singleton object singleton. The privateVar variable cannot be accessed outside of the anonymous function. It is the private variable of the singleton object and can only be accessed inside the function or through exposed methods. This form is known as the modular pattern.

Lazy instantiation

The singleton is either a literal or a private member singleton, both of which are created when the script loads, but sometimes the page may never use the singleton, which can be wasteful. In this case, the best way to handle it is lazy loading, which means you don't actually instantiate the singleton until you need to. How do you do that?


var singleton = (function () {
      function init() {
        var privateVar = "private";
        return {
          prop: "value",
          method: function () {
            console.log(privateVar);
          }
        }
      }
      var instance = null;
      return {
        getInstance: function () {
          if (!instance) {
            instance = init();
          }
          return instance;
        }
      }
    })();

The code to create the singleton is first encapsulated in the init function, then a private variable, instance, is declared to represent an instance of the singleton, and a method, getInstance, is exposed to obtain the singleton.
It is called via singleton.getInstance (), and the singleton object is created when getInstance is called.

Applicable occasions

The singleton pattern is the most commonly used design pattern in JS and should be used whenever possible in terms of enhancing modularity and code organization. It organizes the relevant code up to 1 for easy maintenance, and for large projects, lazy loading of each module improves performance, conceals implementation details, and exposes the common api. Common libraries such as underscore and jQuery can be understood as singleton applications.

Combined with the practical

As mentioned earlier, singleton is one of the most commonly used design patterns. Let's take an example to illustrate this.
The following code mainly implements a simple date helper class, which is implemented through singleton pattern:

The basic singleton pattern structure


var dateTimeHelper = {
      now: function () {
        return new Date();
      },
      format: function (date) {
        return date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate();
      }
    }; 
console.log(dateTimeHelper.now());

This code implements the singleton pattern through object literals, and calls methods directly when used.

Lazy loading implements the singleton pattern


 var dateTimeHelper = (function () {
      function init() {
        return {
          now: function () {
            return new Date();
          },
          format: function (date) {
            return date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate();
          }
        }
      }
      var instance = null;
      return {
        getInstance: function () {
          if (!instance) {
            instance = init();
          }
          return instance;
        }
      }
    })(); 
console.log(dateTimeHelper.getInstance().now())

This is the lazily loaded singleton pattern.

Here are a few more examples:
Implementation 1: Simplest object literals


var singleton = {

    attr : 1,

    method : function(){ return this.attr; }

  }



var t1 = singleton ;

var t2 = singleton ;

So obviously, t1 === t2.

A score of 10 is simple and very useful, but the downside is that there is no encapsulation, and all attribute methods are exposed. For those cases where private variables are needed, the spirit is willing but the spirit is weak. Of course, there is also a definite drawback on this.

Implementation 2: Constructor internal judgment

It's a bit like the original JS implementation, except that you put the judgment on whether an instance of the class already exists inside the constructor.


function Construct(){

  //  Make sure there are only singletons 

  if( Construct.unique !== undefined ){

    return Construct.unique; 

  }

  //  Other code 

  this.name = "NYF";

  this.age="24";

  Construct.unique = this;

}



var t1 = new Construct() ;

var t2 = new Construct() ;

So there is, t1 === t2.

It is also very simple. It is nothing more than to propose an attribute to make a judgment, but there is no security in this way. Once I modify the unique attribute of Construct externally, the singleton pattern will be broken.

Implementation 3: Closure mode

For the famously flexible JS, there are n answers to any question, but it's up to me to weigh them against each other. Here are a few simple ways to implement the singleton pattern using closures, which is nothing more than creating a singleton cache.


var single = (function(){

  var unique;

  function Construct(){

    // ...  Code to generate a singleton constructor 

  }



  unique = new Constuct();



  return unique;

})();

var t1 = single; var t2 = single; Can. Similar to object literals. But it's a little bit safer, but it's not absolutely safe.

If you want to call single(), you just need to change the internal return to something else


  return function(){

    return unique;

  } 

This can also be done using new (formalist haste). Of course, this is just one example of a closure, but you can also tell whether a singleton exists in Construct, and so on. A variety of ways in different situations to do the choice.


conclusion

The benefit of the singleton pattern is that it organizes the code, encapsulating related properties and methods in an object that will not be instantiated multiple times, making code maintenance and debugging easier. Implementation details are hidden to prevent incorrect modifications and global namespace contamination. In addition, lazy loading can improve performance and reduce unnecessary memory consumption.


Related articles: