Peter Seibel, author of Practical Common Lisp, once said that if you need a pattern, something must be wrong. The problem he mentioned refers to the need to seek and summarize a general solution because of the inherent flaws of language.
Whether it is a weak or strong type, a static or dynamic language, an imperative or descriptive language, each language has its own advantages and disadvantages. A Jamaican athlete has some advantages in sprinting and even boxing, but lacks some in practicing yoga.
Warlocks and Shadow Priests can easily be an excellent auxiliary, while an enemy magic flying around with Macon on his back would be slightly awkward. To switch to the program, it may take a lot of effort to implement the decorator in the static language. Because js can throw methods on objects at any time, the decorator pattern becomes useless in js.
There are quite a few books about Javascript design patterns. "Pro javaScript Design Patterns" is a classic book, but the examples in it are quite verbose, so based on the code I wrote at work, I will summarize my understanding. If my understanding is biased, please make sure to correct it.
1. Singleton mode
The definition of a singleton pattern is to produce a unique instance of a class, but js itself is a "classless" language. Many articles that talk about js design pattern use {} as a singleton and make sense. Because there are many ways to generate objects by js, let’s take a look at another more meaningful singleton.
There is a common requirement that when clicking a button, a mask layer needs to pop up on the page. For example, when you click on web.qq.com to log in.
This code that generates a gray background mask layer is easy to write.
The code copy is as follows:
var createMask = function(){
return document,body.appendChild( document.createElement(div) );
}
$( 'button' ).click( function(){
Var mask = createMask();
mask.show();
})
The problem is that this mask layer is globally unique, so every time you call createMask, a new div will be created, although it can be removed while hiding the mask layer. However, it is obviously unreasonable to do this.
Let’s look at the second solution, create this div at the beginning of the page. Then refer to it with a variable.
The code copy is as follows:
var mask = document.body.appendChild( document.createElement( "div' ) );
$( "button' ).click( function(){
mask.show();
} )
This does not mean that only a mask layer div will be created on the page, but another problem will follow. Maybe we will never need this mask layer, which will waste a div and you should be very stingy about any operation of the dom node.
If you can use a variable, determine whether a div has been created?
The code copy is as follows:
var mask;
var createMask = function(){
if ( mask ) return mask;
else{
mask = document,body.appendChild( document.createElement(div) );
return mask;
}
}
It looks good, but here I did complete a function that generates a single column object. Let's take a closer look at what's wrong with this code.
First of all, this function has certain side effects. The function changes the reference to the external variable mask in the function body. In a multi-person collaboration project, createMask is an unsafe function. On the other hand, the global variable mask is not a necessary one. Let's improve it.
The code copy is as follows:
var createMask = function(){
var mask;
return function(){
return mask || ( mask = document.body.appendChild( document.createElement('div') ) )
}
}()
A simple closure is used to wrap the variable mask, at least for the createMask function, it is closed.
Maybe when I see this, I think the singleton pattern is too simple. Indeed, some design patterns are very simple. Even if I have never paid attention to the concept of design patterns, I have used some design patterns in my daily code without knowing it. Just like when I understood what an old man’s cart is, I thought about it many years ago, it turned out that this is an old man’s cart.
The 23 design patterns in GOF are also patterns that have existed and used repeatedly in software development. If the programmer does not clearly realize that he has used certain patterns, then he may miss a more suitable design next time (this passage comes from "The World of Programming in Matsumoto".
Let’s go back to the topic, the previous singleton still has its disadvantages. It can only be used to create mask layers. What if I need to write a function to create a unique xhr object? Can I find a general singleton wrapper?
Functions in js are the first type, which means that functions can also be passed as parameters. Let’s take a look at the final code.
The code copy is as follows:
var singleton = function( fn ){
var result;
return function(){
return result || ( result = fn .apply( this, arguments ) );
}
}
var createMask = singleton( function(){
return document.body.appendChild( document.createElement('div') );
})
Use a variable to save the first return value. If it has been assigned, the variable will be returned first in subsequent calls. The code that really creates the mask layer is passed to the singleton wrapper through the callback function. This method is actually called the bridge mode. Regarding the bridge mode, it is put a little later.
However, the singleton function is not perfect, it always requires a variable result to register the reference to the div. Unfortunately, the functional characteristics of js are not enough to completely eliminate declarations and statements.