04 [JavaScript Design Pattern] Singleton Mode

Write in front

This series of articles is based on the study of the book "JavaScript Design Patterns". At first, I felt that when I was learning, I only need to read the book and I don’t need to take additional notes. But later I found that some of the content in the book is not understandable. It’s not easy, so I sorted out my understanding based on the description in the book and recorded it. I hope to learn with you. If there is something I understand wrong in the article, please criticize and correct, and everyone can make progress together~

From this article, we begin to really learn JavaScript design patterns, first of all, learn the first design pattern-singleton pattern.

 

Singleton mode meaning

The singleton pattern is actually the simplest and most common design pattern in JS, and its meaning is relatively simple: to ensure that a class has only one instance, and only provide a global access point to access it. If this sentence is not easy to understand, let me give you another chestnut: The JS library file that we introduce into the project code by CDN is actually a singleton, such as our jQuery. When we introduce jQuery through the <script> tag in the page, we can use the "$" symbol in the JS code to access all methods in jQuery. The $ symbol here is actually the only access point provided by jQuery to the outside world, and it is also jQuery. The only instance of an object, we can understand that.

 

Singleton mode application scenarios

There are actually many application scenarios for singleton mode. For example, if we only need one object for some objects, we can use singleton mode, such as thread pool, global cache, browser window object, etc., as well as when we interact with the front and back ends. Singletons can be used for database connections, webSocket connections, etc., and some front-end UI components can also use singletons, such as those pop-ups. The simplest is to log in to the pop-up. If the user is logged in, the login pop-up window will not be displayed. If the user is not logged in, the pop-up window will be displayed after the user clicks the login button. When the pop-up window is displayed, we cannot create a pop-up window for him every time he clicks the login button. Well, you can only create a pop-up window first, and display it when the user clicks the button, so that you can ensure that there is only one login pop-up window in your entire application, instead of giving it every time you click the login button He created multiple pop-up windows causing unnecessary DOM waste.

 

Singleton mode realization idea

As mentioned in the above application scenario, you only need to control whether the pop-up window is displayed every time you click the button, and you do not need to create a new pop-up window every time. How to realize such a requirement is actually very simple. We only need to define a variable. This variable is used to mark whether the pop-up window or a singleton has been created. If it is created, it will return the created object, if not created Just create a new object. Therefore, the realization of the singleton pattern can be completed with only one variable.

 

Specific implementation of singleton mode

1. Normal realization

Here we do not discuss the implementation process of the singleton pattern in traditional languages, because JS itself is a programming language without "classes". Although the concept of classes was added at the beginning of ES6, it is more of a syntactic sugar. Therefore, the implementation of the singleton pattern in JS is not the same as the implementation process in traditional programming languages, and there is no need to copy the implementation process of the singleton pattern in traditional languages ​​into JS. It can be said that it is easier to implement singleton mode in JS.

The core concept of the singleton mode is actually only two points: to ensure that there is only one object, and provide global access.

Then in JS, the object we create through the object literal method can guarantee the condition of "only one object". Secondly, we define this object in the global scope to meet the condition of "providing global access". So in combination, through the way of object literals, objects defined in the global scope completely meet the two conditions of the singleton mode, so the simplest way to implement the singleton mode in JS is as follows:

var objectA = {};    //定义在全局作用域中

However, although the above method implements the singleton mode, there is a problem. Defining the object in the global scope will cause environmental pollution in the scope, and it is very likely that this object will be inadvertently modified somewhere later in the code. Happening. We solve these two problems in the following two ways:

1. Use namespace

The use of namespaces does not actually solve the problem of global scope pollution, but to a certain extent it can reduce the number of variables in the global scope, as follows:

        var nameSpaceA = {
            objectA: function() {

            },
            objectB: function() {

            }
        };

In the above code, we directly define objectA and objectB as attributes of nameSpaceA, which reduces the number of variables in the global scope, and to some extent avoids the opportunity for variables to directly interact with the global scope.

2. Use closures to encapsulate private variables

In addition to the namespace approach, we can use closures to directly encapsulate some variables as private variables, as follows:

        var objectB = (function() {
            var _name = 'www.xbeichen.cn';
            var _age = 25;
            return {
                getInfo: function() {
                    return `${_name}的年龄已经是${_age}岁了哦`;
                }
            }
        })();

In the above code, we encapsulate the two variables _name and _age with closures, so that these two variables cannot be accessed in the global scope.

Two, inert singleton

Lazy singleton is a key point in the singleton pattern, and its meaning is very simple: create objects when needed, not at the beginning.

Let’s use the login window as an example. If we don’t use a lazy singleton, it may be implemented in this way: when we enter the system, this login popup will also be created, but at this time it is hidden. When the user clicks the login button, its display properties will change, and it will pop up the login panel for the user to log in. But one problem with this is that if the user opens the webpage just to see other information on the webpage, but does not want to log in, is it just creating a login pop-up window, but it is not used, which causes the DOM Waste.

If a lazy singleton is used, it may be the case: when we enter the system, the login pop-up window will not be created at the beginning, only when the user clicks the login button, will it be created and displayed , In this way, redundant DOM waste is avoided. However, there is a problem with this. This only achieves the characteristics of laziness, and does not have the effect of a singleton, because this pop-up window is created every time you click. This problem is actually very simple to solve. We define a variable to mark Whether to create a pop-up window is fine, so that the effect of a lazy singleton is achieved, as follows:

        //惰性单例
        var createLoginView = (function() {
            var div;
            return function() {
                if(!div) {
                    div = document.createElement('div');
                    div.innerHTML = '登录弹窗';
                    div.style.display = 'none';
                    document.body.appendChild(div);
                }

                return div;
            }
        })();

        document.getElementById('loginButton').onclick = function() {
            var loginView = createLoginView();
            loginView.style.display = 'block';
        }

In the above code, we have implemented a lazy singleton, but this code violates the single responsibility principle. All the logic is inside the createLoginView object. If we want to create iframe and script tags later, we need to modify the code inside createLoginView. Have to copy it again, this is a very bad thing.

We implement a general lazy singleton in the following way:

        //通用的惰性单例
        var getSingle = function(fn) {
            var result;
            return function() {
                return result || (result = fn.apply(this,arguments));
            }
        };

        var createLoginView = function() {   //创建div
            var div = document.createElement('div');
            div.innerHTML = '登录弹窗';
            div.style.display = 'none';
            document.body.appendChild(div);
            return div;
        };
        var createSingleLoginView = getSingle(createLoginView);

        var createIframeView = function() {   //创建iframe
            var iframe = document.createElement('iframe');
            document.body.appendChild(iframe);
            return iframe;
        };
        var createSingleIframeView = getSingle(createIframeView);

        document.getElementById('loginButton').onclick = function() {
            var loginView = createSingleLoginView();
            loginView.style.display = 'block';
        }

        document.getElementById('iframeButton').onclick = function() {
            var iframeView = createSingleIframeView();
            iframeView.src = 'http://www.xbeichen.cn';
        }

In the above code, we put the code to create the label object and the code to manage the singleton in different methods. These two methods do not affect each other, but when they are used in combination, the realization of the singleton mode is completed. This is undoubtedly very successful.

 

to sum up

In this article, we introduce the implementation of the simplest singleton pattern in JS. When introducing it, we did not copy it mechanically like in traditional languages, but made full use of the characteristics of the JS language to implement it, including the implementation of lazy singletons. In the example, the knowledge points of high-order functions and closures in JS are used, so you still need to have a certain advanced basic knowledge of JS before learning design patterns.

Guess you like

Origin blog.csdn.net/qq_35117024/article/details/105816702