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