• A design pattern is a concise and elegant solution to a particular problem in a particular context
  • The singleton pattern is particularly prominent in JS (every object literal can be considered a singleton ~)

Singleton pattern (Singleton pattern)

1. Definition & Implementation ideas

Ensure that there is only one instance (of a class) and provide global access.

2. Implementation of singleton pattern in JavaScript

  • In JavaScript, a singleton acts as a namespace provider, providing a unique access point to the object from the global namespace.

  • In JS development, we often use global variables as singletons

2.1 The simplest object literal

Let’s look at the definition of the singleton pattern: [Ensures that (a class) has only one instance and provides global access]

var Sinleton = {
  attr: 1.show() {
    return this.attr
  }
}
var t1 = Sinleton
var t2 = Sinleton
console.log(t1 === t2) // true
Copy the code

I’m going to create this object Sinleton,

  1. The Sinleton object is truly unique.
  2. If the Sinleton variable is declared in global scope, then we can use the variable anywhere in our code.

This satisfies both conditions for the singleton pattern.

Pros: Simple and practical

Disadvantages:

  1. There is little encapsulation and all property methods are exposed. For some cases where private variables are needed, it’s hard
  2. There are some drawbacks to this question.

2.2 Internal judgment of the constructor

function Singleton(name, age) {
  if(Singleton.unique) {
    return Singleton.unique
  }
  this.name = name
  this.age = age
  Singleton.unique = this
}
var t1 = new Singleton('cherish'.18)
var t2 = new Singleton('silence'.18)
console.log(t1 === t2) // true
Copy the code

Disadvantages: An attribute is proposed for judgment, but there is no security. Once the unique attribute of Construct is externally modified, the singleton pattern is broken.

2.3 Using closures to implement the singleton pattern

  • Use closures to cache the created singleton
var Singleton = (function() {
   function Construt() {}return new Construt()
})()

var t1 = Singleton
var t2 = Singleton
console.log(t1 === t2) // true
Copy the code

Similar to object literals. But it’s a little safer, but it’s not absolutely safe. If you want to use it with a single() call, just change the internal return

var Singleton = (function() {
  var constance = null
  return function Construt() {
    if(! constance) { constance =this
    }
    return constance
  }
})()

var t1 = new Singleton('cherish'.18)
var t2 = new Singleton('silence'.18)
console.log(t1 === t2) // true
Copy the code

3. The traditional method implements the singleton pattern

Key: Ensure that a class has only one instance. 1. Check whether an instance exists and return if it does. A class has a getInstance static method that gets the instance, returning a reference to the singleton instance object and ensuring that it is always the same instance object. 2. Ensure that a class has only one instance object. Define the constructor of the class as a private method to prevent other functions from using the constructor to instantiate the object, and only get a unique instance of the class through the static method of the class.Copy the code

3.1 Implementing a Simple singleton Pattern (opaque)

class Singleton {
  constructor(name) {
    this.name = name;
    this.instance = null;
  }
  static getInstance(name) {
    if (!this.instance) {
      this.instance = new Singleton(name);
    }
    return this.instance;
  }
  getName() {
    return this.name; }}// getInstance: closure + private variable implementation
Singleton.getInstance = (function () {
  let instance = null;
  return function (name) {
    if(! instance) { instance =new Singleton(name);
    }
    returninstance; }; }) ();Copy the code

Disadvantages:

  1. Opaque. The consumer must study the implementation of the code to get the Singleton via singleton.getInstance ().
  2. There is no guarantee that a Singleton class has only one instance object. Users can still instantiate objects with the new keyword.

3.2 Implement transparent singleton pattern

var Singleton = (function () {
  var instance = null;
  var createDiv = function (html) {
    if(! instance) {this.init(html);
    }
    return (instance = this);
  };
  createDiv.prototype.init = function (html) {
    var divObj = document.createElement("div");
    divObj.innerHTML = html;
    console.log(document.body.appendChild, divObj, html);
    document.body.appendChild(divObj);
  };
  returncreateDiv; }) ();var a = new Singleton("<span>aaa</span>");
Copy the code

3.3 + Cache proxy, after combination, to achieve reusable singleton pattern

Functionality unpacking: Separate CreateDiv and move the logic responsible for managing the singleton into the proxy class, ensuring that there is only one object. In this way, CreateDiv becomes a normal class that can be combined with the proxy to achieve singleton effect.

class Creatediv {
  constructor(html) {
    this.init(html);
  }
  init(html) {
    const divObj = document.createElement("div");
    divObj.innerHTML = html;
    document.body.appendChild(divObj); }}const SingletonProxy = (function () {
  let instance = null;
  return function (html) {
    if(! instance) { instance =new Creatediv(html);
    }
    returninstance; }; }) ();const a = new SingletonProxy( I am a span tag 1);
const b = new SingletonProxy(" I am a span tag 2");
console.log(a === b);
Copy the code

3.4 Single responsibility — landing floating window optimization

// The call is created as soon as the page is loaded
// combine with global variables
var getSingle = function (fn) {
  let instance = null;
  return function () {
    if(! instance) { instance = fn(... arguments) }return instance;
  };
};
var createLoginLayer = function () {
  loginLayerObj = document.createElement("div");
  loginLayerObj.innerHTML = "<span>i am a loginLayObj</span>";
  loginLayerObj.style.display = "none";
  document.body.appendChild(loginLayerObj);
  return loginLayerObj
}
var btnObj = document.querySelector("#loginBtn");
btnObj.addEventListener("click".() = > {
  const loginLayerObj = getSingle(createLoginLayer);
  loginLayerObj.style.display = "block";
});
Copy the code

4. Front-end application scenarios

  • The window object of the browser. In JavaScript development, singleton implementations are often used for objects that require only one.

  • Mask, landing window, etc.

5. Other scenarios

The application scenarios of singleton mode are generally found under the following conditions:

(1) In the case of resource sharing, avoid performance or loss caused by resource operation. As in the log files above, apply the configuration.

(2) In the case of controlling resources, it facilitates the communication between resources. Such as thread pools.

Such as:

  • Windows Task Manager and Recycle Bin

  • The counter of the website is generally realized by singleton mode, otherwise it is difficult to synchronize. A counter tells you about the number of visits to a particular page of your site.

  • The thread pool. The design of multi-threaded thread pool usually adopts singleton mode, because thread pool should be convenient to control the threads in the pool.

  • Global cache and so on.

6. Avoid/reduce naming pollution of global variables

Global variables are prone to namespace contamination. In medium to large projects, many of these variables can exist in programs if they are not limited and managed. Variables in JavaScript can also easily be accidentally overwritten. As normal developers, it is important to minimize the use of global variables and, if necessary, to minimize their pollution. There are several ways to reduce naming pollution associated with global variables.Copy the code

A common way to avoid global variable contamination in development is as follows:

  • Global namespace
  • Using closures

What they all have in common is the ability to define their own members and store data. The difference is that all methods and attributes of a global namespace are public, whereas closures can be privatized.

6.1 Using namespaces

6.1.1 Object literals

var nameSpace = {
  a: function () {
    console.log("a");
  },
  b: function () {
    console.log("b"); }};Copy the code

6.1.2. Create namespaces dynamically

var myApp = {};
myApp.nameSpace = function (name) {
  var parts = name.split(".");
  let current = myApp;
  for (let i in parts) {
    if (!current[parts[i]]) {
      current[parts[i]] = {};
    }
    current = current[parts[i]];
  }
};
myApp.nameSpace("cherish.name");
myApp.nameSpace("silence.age");
// The above code is equivalent to:
var MyApp = {
  cherish: {
    name: {},},silence: {
    age: {},}};Copy the code

6.2 Encapsulating private variables with closures

var nameSpace = (function () {
  let _name = 'cherish'
  return {
    getInfo() {
      return _name
    }
  }
})()
console.log(nameSpace.getInfo());
Copy the code

7. To summarize

Design patterns focus on the abstraction of relationships between objects, while singleton patterns have only one object.

Intermediate classes are often used in development to implement special functions that the original class does not have. ———— implements reusable singleton patterns in conjunction with caching proxies.

If you strictly need a class of an instance object (although JS has no concept of a class), then consider using the singleton pattern.

Using data cache to store the singleton and determine whether the singleton has been generated is the main implementation idea of singleton pattern.

reference

  • A singleton of JavaScript design patterns
  • A common application scenario for design patterns — singletons