The js design modes accumulated here are mainly considered for the development of React Native and UniApp for the time being

Js common design patterns

@[toc]

I. Factory model

Instead of exposing the concrete logic that creates the object, the logic is encapsulated in a function, which is treated as a factory

function createPerson(name, age){
  var o = new Object(a);// Create an object
  o.name = name;
  o.age = age;
  o.sayName = function(){
   console.log(this.name)
  }
  return o;  // Return this object
}
var person1 = createPerson('ccc'.18)
var person2 = createPerson('www'.18)
Copy the code

2. Singleton mode

Ensure that a class has only one instance and provide an access point from which it can be accessed

2.1 writing method 1 (Construct instance)

class Singleton {
    // constructor
    constructor(name) {
        this.name = name;
    }
    // Instance method
    getName() {
        console.log(this.name);
    }
    // Static methods get instance objects
    static getInstance(name) {
        if (!this.instance) {
            this.instance = new Singleton(name);
        }
        return this.instance; }}// Create static attributes as unique identifiers
Singleton.instance = null;
/ / verification
var a = Singleton.getInstance('a');

Copy the code

2.2 Writing Method 2 (Export singleton)

class UserModel {

}

const userModel = new UserModel();
export default userModel;
Copy the code

Observer model

When the state of an object changes, all dependent objects are notified.

Often used for event subscriptions, and for two-way data binding in the Vue framework.

// Publisher (Sales Office)
class SalesOffices{
    constructor(){
        // Cache list (sales roster)
        this.clientList = [];
    }
    // Subscribe function (subscribe message)
    listen(fn){
        this.clientList.push(fn);
    }
    // Publish function (publish sales information)
    trigger(){
        // Go through the roster and send them a message
        for(var i=0; i<this.clientList.length; i++){var fn = this.clientList[i];
            fn.apply(this.arguments); }}}/ / instantiate
var salesOffices = new SalesOffices();
// Xiaoming subscribs to the sales news
salesOffices.listen(function(price){
    console.log("Xiao Ming" + price);
});
// Xiao Hong subscribed to the sales news
salesOffices.listen(function(price){
    console.log("Little red" + price);
});
// Sales office releases sales information
salesOffices.trigger("Hello, today's house price is twenty thousand square!");
// Print the result:Hello, Xiao Ming, today's room rate is2One thousand ping. Hello, Xiao Hong, today's room rate is2One thousand ping.// Subscribe to the message
myDiv.addEventListener('click'.function(){
    console.log("MyDiv is clicked.")});// Publish the message
myDiv.click();

Copy the code

Constructor pattern

Using the new operator, the constructor is called to create a new instance.

There are generally the following steps:

  1. Create a new object
  2. Assign the constructor’s scope to the new object (so this refers to the new object)
  3. Execute the code in the constructor (add attributes to this new object)
  4. Return a new object

The constructor pattern differs from the factory pattern:

  1. There is no explicit creation object
  2. Attributes and methods are assigned directly to this object
  3. No return statement
function Person(name , age){
  this.name = name;
  this.age = age;
  this.sayName = function(){
    console.log(this.name)
  }
}

var person1 = new Person('ccc'.18)
var person2 = new Person('www'.18)
person1.sayName()      // --> 'ccc'

console.log(person1 instanceof Person)      // --> true

Copy the code

5. Agency mode

Provides a proxy or placeholder for an object to control access to it.

advantages

  1. Protected objects
  2. Optimize performance and reduce overhead objects
  3. Cache the results

5.1 Protection agent

Do some preliminary processing on the incoming data, such as formatting, processing types, filtering fields and so on

// Protect the proxy
		function do1(value){
			console.log(value)
		}
		function xdo1(value){
			if(value==undefined||value==null) {console.log("Non-compliant input")
				return
			}
			value = (' ' + value).replace(/ sand \s* carving /g.'* *');
			if(typeof(value)! ='String'){
				do1(value.toString())
				return
			}
			
			do1(value)
		}
		xdo1()
		xdo1(123123)
		xdo1({})
		xdo1("eqweqwrqw")
		xdo1("Are you a sand sculpture?")

Copy the code

5.2 virtual Proxy

A typical example of this is to make some controls before accessing the main function. If the data is valid, then send it to the main function, otherwise it will automatically return the anti-shake, throttling and image placeholder

If an event is triggered within n seconds, the function execution time will be recalculated.
// Application scenario: Check whether there is no input after the interval of user input
/ * * *@desc Function stabilization *@param Func function *@param Number of milliseconds to delay wait execution *@param Immediate true The table is executed immediately. False The table is not executed immediately */
let timeout={
    // 'default':null
};
let debounce = (func, wait=500, immediate = true,key='default') = > {
    if (timeout[key]) clearTimeout(timeout[key]);
    if (immediate) {
        letcallNow = ! timeout[key]; timeout[key] =setTimeout(() = > {
            timeout[key] = null;
        }, wait)
        if (callNow) func()
    } else {
        timeout[key] = setTimeout(function() { func() }, wait); }}// throttling By throttling, we mean that events are fired continuously but the function is executed only once in n seconds. Throttling dilutes the execution frequency of the function.
// Application scenario: Use for diluting execution efficiency, such as listening for scroll bars while lazy loading.
/ * * *@desc Function throttling@param Func function *@param Number of milliseconds to delay wait execution *@param Immediate true indicates that the command is executed immediately. False indicates that the command is not executed immediately. */

let previous = 0;
let throttle = (func, wait, immediate = false,key='default') = > {
    if (immediate) {
        let now = Date.now();

        if(now - previous > wait) { func(); previous = now; }}else {
        if(! timeout[key]) { timeout[key] =setTimeout(() = > {
                timeout[key] = null;
                func();
            }, wait)
        }
    }
}
export default {
    debounce,
    throttle,
}

Copy the code

5.2. Caching proxy

Caching proxy is a way to cache the results when large computations are needed, and directly return the results when the same input parameter is encountered, which can improve performance

listadd=(list) = >{
    return list.reduce(function(start,value,index,list){
        return start+value
    },0)}// Use closures to save a global variable
var proxy=(function(){
    var chace={}
    return function(.arguments){
        let item=arguments.join(', ')
        if(chace[item]>=0) {return chace[item]+'slow'
        }else{
            let value=listadd(arguments)
            chace[item]=value
            return value
        }
    }
})()
console.log(proxy(1.2.3.4))
console.log(proxy(1.2.3.4))
console.log(proxy(1.5.3.4))
console.log(proxy(1.2.3.4))
console.log(proxy(1.23.4.5))
console.log(proxy(1.23.4.5))

Copy the code

6. Prototype mode

With the prototype chain initializer parameter, it omits the part that passes the constructor parameter initializer parameter.

Disadvantages: All instances will get the same attribute value by default

function Person(){
}
Person.prototype = {
 constructor: Person,
 name: 'ccc'.age: 18.friends: ['www'.'aaa'].sayName: function () {
 console.log(this.name)
 }
}
var person1 = new Person()
var person2 = new Person()

person1.friends.push('bbb')

console.log(person1.friends)  // --> ["www", "aaa", "bbb"]
console.log(person2.friends)  // --> ["www", "aaa", "bbb"]
console.log(person1.friends === person2.friends)  // --> true
Copy the code

Here is a bit of JS knowledge

1. In javascript, there is no real class; methods are treated as a class

Function Person(){} function Person(){

3, but const Person=function is an anonymous function definition method that needs to be initialized first before being used

Use a combination of constructor and stereotype patterns

The most common way to create custom types is to combine the constructor pattern with the stereotype pattern. The constructor pattern is used to define instance properties, while the stereotype pattern is used to define method and shared properties. This approach also supports passing parameters to the constructor.

function Person(name, age){
 this.name = name;
 this.age = age;
 this.friends = ['aaa'.'bbb']
}
Person.prototype = {
 constructor: Person,
 sayName: function(){
 console.log(this.name)
 }
}
var person1 = new Person('ccc'.18)
var person2 = new Person('www'.18)
person1.friends.push('ddd')

console.log(person1.friends)  // --> ["aaa", "bbb", "ddd"]
console.log(person2.friends)  // --> ["aaa", "bbb"]
console.log(person1.friends === person2.friends)  // --> false
console.log(person1.sayName === person2.sayName)  // --> true
Copy the code

Dynamic prototyping

Determine whether a stereotype needs to be initialized and in which direction it should be initialized by checking whether a method that should exist is valid.

function Person(name, age){
 / / property
 this.name = name
 this.age = age
 / / method
 if(typeof this.sayName ! = ='function'){
 Person.prototype.sayName = function(){
  console.log(this.name)
 }
 }
}

var person1 = new Person('ccc'.18)
person1.sayName()  // --> ccc
Copy the code