preface

I wanted to write ´ simple factory mode, singleton mode, Observer mode, publish/subscribe mode with ES3. , found time to review several small questions, expand to ES3, ES5, ES6, and make notes (again worship the company’s problem makers).

Full version github code address: github.com/xuhuihui/sm…

Notes to be taken:

  1. Implementing simple template strings (6 points)
    • ${} implements the ES6 template string.
    • There is no need to worry about escape and nesting of special symbols ($, {,});
  2. A simple simulation implementation of React-Redux

Simple Factory model

define

Define an interface for creating objects and let subclasses decide which class to instantiate. The Factory Method delays the instantiation of a class to its subclasses.

Scope of application

It is suitable for complex logic judgment, such as a series of complex logic judgment, such as putting on the shelf, selling, ordering, shipping, delivery, hand and so on.

For complex logic judgment, there are two solutions, the policy pattern and the factory pattern. 2. Policy mode: a more elegant way to write complex JavaScript judgments

implementation

Es3 code

Var createPop = function (type, text) {// Create an Object and extend it var o = new Object(); o.content = text; O.show = function () {alert(type + ':' + this.content); Switch (type) {case 'alert': // Alert box difference part break; Case 'confirm': // break; Case 'prompt': // Prompt difference part break; }}; return o; };Copy the code

Es6 code

class Image {} class Link {} class Text {} class ElementFactory { createElement(type, option){ const ELEMENT = { "image" : Image, "text" : Text, "link" : Link } let ElementConstructor = ELEMENT(type), element = null; if(ElementConstructor){ element = new ElementConstructor(option); } return element; }}Copy the code

The singleton pattern

define

  • Make sure there is only one instance
  • Global access

Scope of application

Applicable to the implementation of the bullet frame, global cache. One way to implement the popbox is to create it first, and then hide it. This will waste some unnecessary DOM overhead. We can create the popbox when we need it, and realize only one instance with the singleton pattern, thus saving some DOM overhead.

implementation

Es3 code

Simplified code

Advantages: Initialized property is used to create only one EasySingletonIns instance forever. 2. Disadvantages: Not closed enough, initialized property can be accessed from outside.

Var EasySingletonIns = {initialized: false, // Instantiate extension: belongTo: undefined, getBelongTo: function () { return EasySingletonIns.belongTo; }}; var EasySingleton = { getInstance: function () { if (EasySingletonIns.initialized) { return EasySingletonIns; } EasySingletonIns.initialized = true; / / instance extension can also write here: EasySingletonIns. BelongTo = 'EasySingleton'; return EasySingletonIns; }};Copy the code
Advanced code

1. Advantages: Use function closures to prevent internal attributes from being changed. 2. Disadvantages: It is not good to dynamically pass in the desired attributes.

var AdvancedSingleton = (function () { var ins = null; return function () { if (ins) { return ins; } if (! (this instanceof AdvancedSingleton)) { return new AdvancedSingleton(); } function Inner() {this.belongto = 'advancedsingleton@constructor '; } Inner.prototype = this.constructor.prototype; // The prototype extension can also be written here: ins = new Inner(); return ins; }; }) ();Copy the code
Cool version code

1, advantages: using apply, you can add methods to the prototype instance of CoolSingletonCreator. 2. Disadvantages: Problems arise when constructors return instances other than their own.

function CoolSingletonCreator(fn) { if (typeof fn ! == 'function') { throw new Error('CoolSingletonCreator fn param must be function! '); } var AdvancedSingletonForCool = (function () { var ins = null; return function () { if (ins) { return ins; } if (! (this instanceof AdvancedSingletonForCool)) { return new AdvancedSingletonForCool(); } var args = arguments; function Inner() { fn.apply(this, args); } Inner.prototype = this.constructor.prototype; ins = new Inner(); return ins; }; }) (); AdvancedSingletonForCool.prototype = fn.prototype; AdvancedSingletonForCool. GetInstance = function () {/ / dynamic parameters: Bind = [null] var args = [null]; return new (Function.prototype.bind.apply(AdvancedSingletonForCool, args.concat.apply(args, arguments)))(); }; return AdvancedSingletonForCool; }Copy the code

Es5 code

var Singleton = function(name) { this.name = name; // a flag to determine whether instances of the class have been created this.instance = null; GetInstance = function(name) {// Create an instance of the class if(! this.instance) { this.instance = new Singleton(name); } return this.instance; }Copy the code

Es6 code

class Singleton { constructor(name) { this.name = name; this.instance = null; } // Construct a well-known interface for users to instantiate the class static getInstance(name) {if(! this.instance) { this.instance = new Singleton(name); } return this.instance; }}Copy the code

Observer model

define

Define a one-to-many dependency between objects so that when an object’s state changes, all dependent objects are notified and refreshed automatically.

Scope of application

1. When the observed data object changes, the corresponding function is automatically called. Such as vue’s bidirectional binding; 2. Whenever a method in an object is called, the corresponding ‘access’ logic is called. For example, the Spy function that powers the test framework;

implementation

Es3 code

1. Method: Use the Prototype binding function.

Var Subject = (function () {// ObserverList () {this.observerList = []; } ObserverList.prototype.add = function (observer) { return this.observerList.push(observer); }; ObserverList.prototype.remove = function (observer) { this.observerList = this.observerList.filter(function (item) {return item ! == observer; }); }; ObserverList.prototype.count = function () { return this.observerList.length; }; ObserverList.prototype.get = function (index) { return this.observerList[index]; }; This. Observers = new ObserverList(); } Subject.prototype.addObserver = function (observer) { this.observers.add(observer); }; Subject.prototype.removeObserver = function (observer) { this.observers.remove(observer); }; Subject.prototype.notify = function () { var observerCount = this.observers.count(); for (let i = 0; i < observerCount; i++) { var observer = this.observers.get(i); observer.update.apply(observer, arguments); } } return Subject; }) ();Copy the code

Es5 code

DefineProperty (obj, props, Descriptor) 2. Disadvantages: Object.defineProperty() does not detect array reference invariant operations (push/pop, etc.); Object.defineproperty () can only detect attribute changes of the Object, i.e. bind object.defineProperty () again if there are deeply nested objects;

 <input id="input" type="text" />

    const data = {}
    const input = document.getElementById('input')
    Object.defineProperty(data, 'text', {
      set(value) {
        input.value = value
        this.value = value
      }
    })
    input.onchange = function(e) {
      data.text = e.target.value
    }
Copy the code

Es6 code

1. Method: Proxy/Reflect is a new feature introduced in ES6 and can also be used to complete the Observer mode. 2, advantages: can hijack the array change; DefineProperty is the hijacking of attributes, Proxy is the hijacking of objects;

var obj = { value: 0 } var proxy = new Proxy(obj, { set: Function (target, key, value, receiver) {reflect. set(target, key, value, receiver)}}) proxy.value = 1 // Call the corresponding functionCopy the code

Publish and subscribe model

define

Definition: Add message brokers to communicate in the observer pattern to achieve more loose decoupling.

Differences between publish/subscribe and Observer:

1. In the observer mode, the observer knows the Subject, and the Subject keeps records of the observer. However, in the publish-subscribe model, publishers and subscribers are unaware of each other’s existence. They communicate only through the message broker. In the publish/subscribe model, components are loosely coupled, as opposed to the observer model. 3. The observer pattern is synchronous most of the time. For example, when an event is triggered, the Subject will call the observer’s methods. The publish-subscribe pattern is asynchronous most of the time (using message queues). 4. The Observer pattern needs to be implemented in a single application address space, whereas publish-subscribe is more like the cross-application pattern.

Scope of application

1. Scope: MVC, MVVC architecture, Vue source code implementation and some small games, etc. 2. Benefits: Deeper decoupling in asynchronous programming. Disadvantages: Creating a subscriber itself takes time and memory, and when you subscribe to a message, the message may never happen, but the subscriber will always be in memory. If a publish-subscribe program is heavily used, it can also make it difficult to track bugs.

implementation

Es5 code

var Event = function() { this.obj = {} } Event.prototype.on = function(eventType, fn) { if (! This.obj [eventType]) {this.obj[eventType] = []} this.obj[eventType].push(fn) // event.prototype.emit = function() { var eventType = Array.prototype.shift.call(arguments) var arr = this.obj[eventType] for (let i = 0; i < arr.length; Arr [I].apply(arr[I], arguments)}} var ev = new Event() ev.on('click', Function (a) {// subscribe function console.log(a) // 1}) ev.emit('click', 1) // Publish functionCopy the code

Es6 code

Class Subject {constructor() {this.subs = [] this.state = 'constructor'} getState() {return this.state} SetState (state) {if (this.state === state) {return} this.state = state this.notify() Trigger notification} addSub(sub) {this.subs.push(sub)} removeSub(sub) {const idx = this.subs.findIndex(I => I === sub) if (idx === = -1) {return} this.subs.splice(idx, 1)} notify() {this.subs.foreach (sub => {sub.update()) })}} // Watch people, Class Observer {update() {console.log('update')}} // Test code const subject = new subject () const ob = new Observer() const ob2 = new Observer() ob2.update = function() { Console. log('laifeipeng')} // The target adds an observer subject.addSub(ob) subject.addsub (ob2) // The target publishes a message calling the observer's update method // subject.notify(); // Trigger subject.setState(' li Si ') by setting the internal state instead of manually triggeringCopy the code

Common design patterns in JavaScript

The design patterns learned are as follows (゚o゚; , after the weekly time will probably fill it (· _ ·; .

Design patterns are divided into three types, a total of 24.

  • Creative patterns: singleton, Abstract Factory, Builder, Factory, prototype.
  • Structural mode: adapter mode, bridge mode, decorative mode, composite mode, appearance mode, share mode, proxy mode.
  • Behavioral patterns: template method pattern, command pattern, iterator pattern, Observer pattern, mediator pattern, memo pattern, Interpreter pattern, state pattern, Policy pattern, responsibility chain pattern, Visitor pattern.