The proxy pattern

Introduction: It creates a proxy object for the target object to control access to the target object. In reality, real estate agents, star brokers and lawyers are all agents.

Realize the real estate agent scene

The landlord gives the house agent to the intermediary management, an intermediary management of multiple houses, it becomes easy to find an intermediary to rent.

/ / house
class House {
  constructor(name) {
    / / name
    this.name = name;
    // In the state of renting
    this.state = "renting";
  }
  / / rent
  rentOut() {
    this.state = "rented";
  }
  // Is it already rented
  hasRent() {
    return this.state === "rented"; }}// Real estate agents
class Agent {
  constructor() {
    // The house collection
    this.weakMap = new WeakMap(a); }// Add a room
  addHouse(house) {
    this.weakMap.set(house, house);
  }
  // Find a house
  hasHouse(house) {
    return this.weakMap.has(house);
  }
  // Rental properties
  rentHouse(house) {
    if (this.hasHouse(house)) {
      if (house.hasRent()) {
        console.log(house.name, "Premises rented");
      } else {
        console.log(house.name, "Available for viewing."); }}else {
      console.log(house.name, "Not available."); }}}const houseA = new House("houseA");
const houseB = new House("houseB");
const houseC = new House("houseC");
const agent = new Agent();
agent.addHouse(houseA);
agent.addHouse(houseB);

//B House for rent
houseB.rentOut();
agent.rentHouse(houseA); //houseA is available for viewing
agent.rentHouse(houseB); The house has been let
agent.rentHouse(houseC); HouseC doesn't have this listing
Copy the code

Variable agent

In fact, variable is also a proxy mode, in the code we set a = 1, a has the proxy permission of the number 1, if we need to assign 1 to other variables, such as b = 1, we can use proxy A, directly b = A

const obj = {
  name: "xiaoming".sayName() {
    // Delegate this variable to _this. Accessing _this is accessing this
    const _this = this;
    function say() {
      console.log(I was `${_this.name}`);
    }
    // Js this will refer to its caller, default to window, strictly undefinedsay(); }}; obj.sayName();Copy the code

Event delegate for DOM elements

In development, we often add events to the same child elements (such as li) at the same level. However, if there are too many child elements, it will incur certain performance overhead to bind events to all of them. Therefore, we use the dom element event capture and then bubble mechanism to bind events to the parent element first, and then capture or bubble to the child element.

<ul id="ul">
    <li data-index="1">1</li>
    <li data-index="2">2</li>
    <li data-index="3">3</li>
    <li data-index="4">4</li>
    <li data-index="5">5</li>
</ul>
Copy the code

capture

ul.addEventListener(
  "click".function (e) {
    const dom = e.target;
    if (dom.tagName === "LI") {
      const index = dom.getAttribute("data-index");
      console.log(The first `${index}Li elements); }},true
);
Copy the code

The bubbling

ul.addEventListener("click".function (e) {
  const dom = e.target;
  if (dom.tagName === "LI") {
    const index = dom.getAttribute("data-index");
    console.log(The first `${index}Li elements); }});Copy the code

Proxy implements responsive data

In VUe2, Object. DefineProperty is used to rewrite the get and set methods of Object attributes, and the implementation relies on collecting and distributing updates. Vue3 uses proxy Object to realize responsive data.

<div class="wrap">
  <input type="text" id="input" />
  <div id="container"></div>
</div>
Copy the code
// The effect function being executed
let active;

// Reactive method
function reactive(target) {
  const weakMap = new WeakMap(a);return new Proxy(target, {
    get(target, name, value, receiver) {
      // Collect dependencies {target: {key: [effect1,effect2]}}
      let map;
      if(! weakMap.has(target)) { weakMap.set(target, (map =new Map()));
      } else {
        map = weakMap.get(target);
      }
      let set;
      if(! map.has(name)) { map.set(name, (set =new Set()));
      } else {
        set = new Set(a); } set.add(active);return Reflect.get(target, name, receiver);
    },
    set(target, name, value, receiver) {
      if(target[name] ! == value) {Reflect.set(target, name, value, receiver);
        // Send updates
        if (weakMap.has(target)) {
          const map = weakMap.get(target);
          if (map.has(name)) {
            constset = map.get(name); set.forEach(effect); }}}},}); }// Target object
const form = {
  input: ""};// The target object becomes responsive data
const proxy = reactive(form);

// Watcher in VUe2, when executing the render function in the effect function to render the DOM, it will access the responsive data, collect the effect, and trigger the update again after the responsive data changes
function effect(fn) {
  active = fn;
  fn();
}

//render the DOM
function render() {
  container.innerText = proxy.input;
}

// Add effect to render function
effect(render);

// Input modifies the reactive value
input.addEventListener("input".function (e) {
  proxy.input = e.target.value;
});
Copy the code

Adapter mode

Convert the interface (methods, attributes) of a class (object) into another interface that users need to solve the problem of interface incompatibility between classes (object). Life multi – interface mobile phone charger, adapter, translator and so on are adapter mode.

Realize multi-interface mobile phone charger

// Multi-port charger
class ChargerAdapter {
  charge(phone) {
    if (phone instanceof Apple) {
      console.log('Charging the iPhone');
    } else if (phone instanceof Android) {
      console.log('Charging your Android phone'); }}}class Apple {}

class Android {}

const chargerAdapter = new ChargerAdapter();
const apple = new Apple();
const android = new Android();

chargerAdapter.charge(apple);
chargerAdapter.charge(android);
Copy the code

Axios is web and Node compatible

Axios supports sending requests on both the Web and Node sides

function getDefaultAdapter() {
  var adapter;
  if (typeofXMLHttpRequest ! = ="undefined") {
    // For browsers use XHR adapter
    adapter = require("./adapters/xhr");
  } else if (
    typeofprocess ! = ="undefined" &&
    Object.prototype.toString.call(process) === "[object process]"
  ) {
    // For node use HTTP adapter
    adapter = require("./adapters/http");
  }
  return adapter;
}
Copy the code

User-defined implementation adapters are also supported

var adapter = config.adapter || defaults.adapter;
Copy the code

Refactoring Ajax for AxiOS

The old project used Ajax to send requests, and if you wanted to use AixOS underneath to send requests without changing the original invocation, you needed to implement an adapter.

// simulate sending a request
function axios(options) {
  return new Promise((resolve, reject) = > {
    setTimeout(() = > {
      resolve(options);
    }, 1000);
  });
}

/ / adapter
function ajaxAdapter(options) {
  const{ success, error, ... axiosOptions } = options;return axios(axiosOptions).then(success, error);
}

// Rewrite the Ajax method to keep it the same
function ajax(options) {
  return ajaxAdapter(options);
}

ajax({
  url: "/demo-url".method: "post".data: {
    name: "Zhang",},success: function (data) {
    console.log("success", data);
  },
  error: function (err) {
    console.log("error", err); }});Copy the code

promisify

The API in Node is implemented asynchronously using callback, and the adapter pattern is used to make it compatible with promise writing

let { readFile } = require("fs");

function promisify(fn) {
  return function (. args) {
    return new Promise((resolve, reject) = > {
      const callback = (err, data) = > {
        if (err) returnreject(err); resolve(data); }; fn(... args, callback); }); }; } readFile = promisify(readFile); readFile("./demo1.html").then((data) = > {
  console.log(data.toString());
});
Copy the code

Vue cross-platform implementation of Canvas painting

Frameworks such as Vue and React implement the middle layer of virtual nodes and provide common apis for operating virtual nodes to run cross-platform.

The following simple implementation uses virtual node to achieve drawing graphics in canvas.

Template =>vnode=> Canvas Mapping object required for drawing graphics => Canvas drawing

// Create a custom renderer method
import { createRenderer } from "@vue/runtime-core";
import App from "./app";
const canvas = document.querySelector("#canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

const drawApi = {
  / / circle painted on canvas
  circle: (ctx, props) = > {
    const { x, y, r, c } = props;
    ctx.fillStyle = c;
    ctx.arc(x, y, r, 0.2 * Math.PI);
    ctx.fill();
  },
  // Draw a rectangle on canvas
  reat: (ctx, props) = > {
    const{ x, y, w, h, c } = props; ctx.fillStyle = c; ctx.fillRect(x, y, w, h); }};// A generic API for manipulating virtual nodes
const nodeOps = {
  // Insert elements
  insert: (child, parent, anchor) = > {
    console.log(child, parent);
    // Determine the parent node is canvas container, which means it is already the outermost layer, start painting
    if (parent === canvas && child) {
      const ctx = canvas.getContext("2d");
      const { tag, props } = child;
      drawApi[tag]?.(ctx, props);
    }
  },
  remove: () = > {},
  // Create the element
  createElement: (tag, isSVG, is, props) = > {
    return {
      tag,
      props,
    };
  },
  createText: () = > {},
  createComment: () = > {},
  setText: () = > {},
  setElementText: () = > {},
  parentNode: () = > {},
  nextSibling: () = > {},
  querySelector: () = > {},
  setScopeId: () = > {},
  cloneNode: () = > {},
  insertStaticContent: () = > {},
  // Add attributes
  patchProp: (vnode, key, oldProp, newProp) = >{ vnode[key] = newProp; }};function createApp() {
  const app = createRenderer(nodeOps).createApp(App);
  app.mount(canvas);
}
createApp();
Copy the code

Corresponding template

export default function app() {
  return (
    <>
      <circle x="100" y="100" r="100" c="red"></circle>
      <reat x="300" y="100" w="200" h="100" c="green"></reat>
    </>
  );
}
Copy the code

The appearance model

Appearance mode is to package some complex processes into an interface for external users to use more easily, users do not need to pay attention to the internal implementation, to provide simple interface for users to use. Household appliances, remote controls, babysitters and so on are all appearance modes.

Analog computer startup

How does it work when you turn on your computer and you don’t have to look inside

/ / parts
//CPU
class CPU {
  start() {
    console.log("Open the CPU"); }}/ / memory
class Memory {
  start() {
    console.log("Open memory"); }}/ / hard disk
class Disk {
  start() {
    console.log("Open the hard drive"); }}/ / computer
class Computer {
  constructor() {
    this.cpu = new CPU();
    this.memory = new Memory();
    this.disk = new Disk();
  }
  start() {
    this.cpu.start();
    this.memory.start();
    this.disk.start(); }}const computer = new Computer();
/ / boot
computer.start();
Copy the code

The code base

The third party library we used in the development, such as jquery, provides $externally to call the internal rich API is also a facade mode

 const$= {css(){},
   style(){},
   animate(){},
   each(){},
   ajax(){}... }Copy the code