Usage of Singleton mode in JavaScript

Source: Internet
Author: User
Tags closure

Singleton mode is a common mode. If you want only one instance for a class in the system, Singleton mode is the best solution.

1. Singleton mode definition

Definition of Singleton mode: ensure that a class has only one instance, and provide a global access point to access it.

II. Implementation principle of Singleton mode

A variable is used to indicate whether an object has been created for a class. If yes, the newly created object is directly returned when you obtain the instance of this class next time.

III. Advantages of Singleton mode

The Singleton mode has the following advantages:

There is only one object in the memory, saving the memory space;
Avoid frequent object destruction and improve performance;
Avoid multiple usage of shared resources;
Global Access.
IV. Implementation of Singleton mode

The core of Singleton mode is to ensure only one instance and provide global access. Therefore, the implementation of Singleton mode is centered on how to ensure the uniqueness of the instance. Therefore, a variable is required to indicate whether an instance object has been created for a class.

There are four main implementation methods:

Method 1: You can use global variables to store the instance. However, global variables are easily overwritten.
Method 2: You can cache the instance in the static attribute of the constructor. The disadvantage is that the static attribute of the constructor is publicly accessible and is easily overwritten externally.
Method 3: wrap the instance in a closure. This ensures the privacy of the instance and prevents the instance from being modified by code other than the constructor. The cost is extra closure overhead.
Method 4: You can override the constructor.
The specific implementation of these four methods is as follows:

4.1 Save the singleton with global variables

Var instance;

Function Cat (){
If (typeof instance = "object "){
Return instance;
    }

// Cat constructor method ......

Instance = this;
}

/* =================== Test code ============================= */
Var cat1 = new Cat ();
Var cat2 = new Cat ();

Console. log (cat1 === cat2); // true
It is risky to use global variables to store the instance objects. This method is not recommended. Because global variables can be overwritten by anyone, they are easy to be overwritten, and the instance object is lost, resulting in unexpected events.

Minimize the use of global variables. Even if necessary, the pollution should be minimized. For example, using namespaces and using closures to encapsulate private variables can minimize the naming pollution caused by global variables.

4.2 Cache instances in the static attributes of constructors

Function Cat (){
If (typeof Cat. instance = "object "){
Return Cat. instance;
    }

// Cat constructor method ......

// Use the static attributes of the constructor to cache the instance
Cat. instance = this;
}

/* =================== Test code ============================= */
Var cat1 = new Cat ();
Var cat2 = new Cat ();

Console. log (cat1 === cat2); // true
This is a very direct solution. Its only drawback is that the static instance attribute of the constructor is public. This attribute may be accidentally modified by other codes.

4.3 Use closures to create objects

Var Cat = (function (){
Var instance,
_ This = this;

Return function (){
If (typeof instance! = "Object "){
// Cat constructor method ......
Instance = _ this;
        }
Return instance;
    }
})();

/* =================== Test code ============================= */
Var cat1 = new Cat ();
Var cat2 = new Cat ();

Console. log (cat1 === cat2); // true
4.4 rewrite the constructor

Function Cat (){
Var instance = this;

// Cat constructor method ......

// Rewrite the constructor
Cat = function (){
Return instance;
    }
}

/* =================== Test code ============================= */
Var cat1 = new Cat ();
Var cat2 = new Cat ();
Console. log (cat1 === cat2); // true
The disadvantage of this mode is that in the constructor rewriting, the constructor will lose all attributes added to it between the initial definition and the time of redefinition.

In the above code, after the constructor is rewritten, no object added to the Cat () prototype has a pointer to the instance created by the original constructor. As follows:

/* =================== Test code ============================= */
// Add attributes to the prototype
Cat. prototype. color = "white ";

Var cat1 = new Cat ();

// After creating the initialization object, add attributes to the prototype again
Cat. prototype. age = "1 ";

Var cat2 = new Cat ();

Console. log (cat1 === cat2); // true
Console. log (cat1.color); // white
Console. log (cat2.color); // white
Console. log (cat1.age); // undefined
Console. log (cat2.age); // undefined
Console. log (cat1.constructor === Cat); // false
Console. log (cat2.constructor === Cat); // false
Cat1.constructor is no longer the same as Cat () constructor because cat1.constructor points to the original constructor instead of the newly defined constructor. Therefore, after the constructor is rewritten, no object added to the Cat () prototype has a pointer to the instance created by the original constructor.

If you want to rewrite the constructor to point the object in the prototype to the original constructor, you can make the following adjustments:

Function Cat (){
Var instance = this;

// Rewrite the constructor
Cat = function (){
Return instance;
    }

// Retain the prototype attributes
Cat. prototype = this;
// Create an instance
Instance = new Cat ();
// Reset the constructor pointer
Instance. contructor = Cat;

// Cat constructor method ......

Return instance;
}

/* =================== Test code ============================= */
// Add attributes to the prototype
Cat. prototype. color = "white ";

Var cat1 = new Cat ();

// After creating the initialization object, add attributes to the prototype again
Cat. prototype. age = "1 ";

Var cat2 = new Cat ();

Console. log (cat1 === cat2); // true
Console. log (cat1.color); // white
Console. log (cat2.color); // white
Console. log (cat1.age); // 1
Console. log (cat2.age); // 1
V. Singleton mode optimization and Practical application

5.1 use closures to encapsulate constructors and instances

Encapsulate the constructor and instance in the execution function. In this way, when the constructor is called for the first time, it creates an object and points the private instance to the object. After the second call, the constructor returns only the private variable. This not only avoids global variable contamination, but also implements Singleton.

Var Cat;
(Function (){
Var instance;

Cat = function (){
If (instance ){
Return instance;
        }

// Use the static attributes of the constructor to cache the instance
Instance = this;

// Cat constructor function implementation ......
//......
};
})();

/* =================== Test code ============================= */
Var cat1 = new Cat ();
Var cat2 = new Cat ();
Console. log (cat1 === cat2); // true
5.2 use proxy to implement Singleton mode

A proxy class can be introduced to implement a class in the proxy and only one instance can be initialized.

Function Cat (){
// Cat constructor method ......
}

Var ProxyCat = (function (){
Var instance;
Return function (){
If (typeof instance! = "Object "){
Instance = new Cat ();
        }
Return instance;
    }
})();

/* =================== Test code ============================= */
Var cat1 = new ProxyCat ();
Var cat2 = new ProxyCat ();

Console. log (cat1 === cat2); // true
The proxy class is introduced. Different from the previous method, the logic for managing a single class is moved to the proxy class. In this way, Cat becomes a common class.

5.3 common inert Singleton

Extract the management Singleton logic from the original code and encapsulate the logic in the getSingle function. The method fn for creating an object is passed into the getSingle function dynamically as a parameter:

Var getSingle = function (fn ){
Var result;
Return function (){
Return result | (result = fn. apply (this, arguments ));
    }
}
Note: This code is excerpted from chapter 4 P68 of JavaScript design patterns and development practices.

In this way, the code of Cat Singleton mode can be rewritten:

Function Cat (){
// Cat constructor method ......
}

Var createCat = getSingle (Cat );

/* =================== Test code ============================= */
Var cat1 = createCat ();
Var cat2 = createCat ();

Console. log (cat1 === cat2); // true
In this example, the responsibilities of creating an instance object and the responsibilities of managing a singleton are put in two methods. These two methods can be independent of each other, the unique instance object is created. Recommended.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.