Definition 1.

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

Implement a singleton pattern

A standard singleton pattern: a variable is used to indicate whether an object has been created for the current class, and if so, the previously created object is returned the next time an instance of the class is fetched.

const single = function (name) {
  this.name = name;
  this.instance = null;
};

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

const a = single.getInstance("coderwhh");
const b = single.getInstance("coderwhh1");
// true
console.log(a === b);
Copy the code

Here we get the unique object of the single class through single.getInstance, which is simple but adds opacity to the class. Users of the single class must be aware that this is a singleton class, as opposed to using new Function to get objects, where you must use single.getInstance.

3. Transparent singleton pattern

Our goal is to implement a “transparent” singleton class that users can use to create this object just like any other normal class. Eg: Use the createDiv singleton class to create a unique div node in the page

const createDiv = (function () {
  var instance = null;
  var createDiv = function (html) {
    if (instance) {
      return instance;
    }
    this.html = html;
    this.init();
    return (instance = this);
  };
  createDiv.prototype.init = function () {
    const div = document.createElement("div");
    div.innerHTML = this;
    document.body.appendChild(div);
  };
  returncreateDiv; }) ();const a = new createDiv("coderwhh");
const b = new createDiv("coderwhh1");
// true
console.log(a === b);
Copy the code

Watch above: Assign a constructor to createDiv. This constructor does two things: 1. Creates the object and performs the init method 2. Ensure there is only one object. If one day we needed to create multiple divs from this class to make the singleton a normal class, then we would have to rewrite the createDiv constructor to remove the code that controls the creation of a unique object.

4. Implement singleton pattern with proxy

Start by removing the code responsible for managing the singleton from the createDiv constructor, making it a normal div class

const createDiv = function (html) {
  this.html = html;
  this.init();
};

createDiv.prototype.init = function () {
  const div = document.createElement("div");
  div.innerHTML = this.html;
  document.body.appendChild(div);
};

const ProxySingleCreateDiv = (function () {
  let instance;
  return function (html) {
    if(! instance) { instance =new createDiv(html);
    }
    returninstance; }; }) ();const a = new ProxySingleCreateDiv("coderwhh");
const b = new ProxySingleCreateDiv("coderwhh1");
// true
console.log(a === b);
Copy the code

The singleton pattern can also be written by introducing a proxy class, so that the logic for managing singleton is moved to ProxySingleCreateDiv, and createDiv becomes a generic class.

5. Singleton pattern in JavaScript

Global variables are not singletons, but in JavaScript development, they are often used as singletons. However, global variables can easily pollute the namespace and can be overwritten by others at any time. As developers, we must reduce the use of global variables. Minimize pollution, even if necessary.

  • Use closures to encapsulate private variables
const user = (function () {
  const __name = "coderwhh";
  return {
    getUserName: function () {
      return__name; }}; }) ();Copy the code

6. Lazy singleton

Inert singleton refers to the need to create an object instance, eg: page is a popup window, the modal window, according to the trigger condition is by clicking on a button and then obviously the modal window on the page is the only, and not always show on the page, so click on the trigger button again to create the popup window.

const createLoginLayer = (function () {
  var div;
  return function () {
    if(! div) { div =document.createElement("div");
      div.innerHTML = "I'm popover.";
      div.style.display = "none";
      document.body.appendChild(div);
    }
    returndiv; }; }) ();document.getElementById("loginBtn").onclick = function () {
  const loginLayer = createLoginLayer();
  loginLayer.style.display = "block";
};
Copy the code

The above example has one obvious drawback: 1. It violates the single responsibility principle, as the logic for creating objects and managing singleton is placed inside the createLoginLayer object 2. The next time you create a unique iframe, span, or other element on the page, you’ll have to rewrite the code above.

7. Generic lazy singleton pattern

In view of the above problems, let’s first isolate the above invariable part.

var obj;
if(! obj) { obj = xxx; }Copy the code

The logic of how to manage singletons is removed from the original code and encapsulated in the gteSingle function, where the object creation method fn is dynamically passed as an argument to the getSingle function

const getSingle = function (fn) {
  var result;
  return function () {
    return result || (result = fn.apply(this.arguments));
  };
};
Copy the code

Next you can create div, iframe tag to try it out

// Create a pop-up
var createLoginLayer = function () {
  var div = document.createElement("div");
  div.innerHTML = "I'm logging in to the floating window.";
  div.style.display = "none";
  document.body.appendChild(div);
  return div;
};
var createSingleLoginLayer = getSingle(createLoginLayer);
document.getElementById("loginBtn").onclick = function () {
  var loginLayer = createSingleLoginLayer();
  loginLayer.style.display = "block";
};

// Create an iframe
var createSingleIframe = getSingle(function () {
  var iframe = document.createElement("iframe");
  document.body.appendChild(iframe);
  return iframe;
});
document.getElementById("loginBtn").onclick = function () {
  var loginLayer = createSingleIframe();
  loginLayer.src = "http://baidu.com";
};
Copy the code

The code above places the responsibility for creating instance objects and the responsibility for managing singletons in two separate methods that can be changed independently without impact. When the two are joined together, the function of creating a unique instance object is completed.