Red Treasure Book Reading Notes Chapter 9

Proxy and reflection The agent feeling is a f...
Agent basis
Proxy catcher and reflection method
proxy pattern
Proxy and reflection

The agent feeling is a feeling of peripheral protection. I first filter the operation, and then pass it to the object

Agent basis

Create proxy

The proxy is created with a constructor and accepts two parameters, the target object and the handler object

const target = { id: 'target' } const handler = {}; const proxy = new Proxy(target,handler); console.log(target.id) console.log(proxy.id); Output: target target

Define catcher

The main purpose of an agent is to define a trap. The catcher is the 'interceptor of basic operations' defined in the handler object. Each handler object can contain zero or more traps, each corresponding to a basic operation, which can be called directly or indirectly on the proxy object. Each time these basic operations are called on the proxy object, the proxy can call the catcher function before these operations are propagated to the target object, so as to intercept and modify the corresponding behavior

That is, the catcher can block the operation, preprocess it, and then pass it to the target object

const target = { foo:'bar' } const handler = { get() { return 'handler ovveride'; } } const proxy = new Proxy(target,handler) console.log(target.foo) console.log(proxy.foo) output bar handler ovveride

Catcher parameters and reflection API s

The get() catcher will receive three parameters: the target object, the property to query, and the proxy object

const target = { foo:'bar' } const handler = { get(trapTarget,property,receiver) { console.log(trapTarget === target) console.log(property) console.log(receiver === proxy) } } const proxy = new Proxy(target,handler) proxy.foo output true foo true

The handwriting catcher is very troublesome, but the global (Reflect) object is paired with the proxy. All methods that can be captured and reflections have API methods with the same name

const target = { foo:'bar' } const handler = { get() { return Reflect.get(...arguments) } } const proxy = new Proxy(target,handler) console.log(proxy.foo) console.log(target.foo) perhaps const target = { foo:'bar' } const proxy = new Proxy(target, Reflect)

Revocable agent

const target = { foo: 'bar' } const handler = { get() { return 'innn' } } const = Proxy.revocable(target,handler) console.log(proxy.foo) console.log(target.foo) revokesss() console.log(proxy.foo)

Utility reflection API

Many reflection methods return a Boolean value called "tag status" to indicate whether the operation was successful, which is sometimes more useful than returning an error

Acting for another agent

Multi layer agents can be used to build a multi-layer interception network

const target = { foo: 'bar' } const firstProxy = new Proxy(target, { get() { console.log('first') return Reflect.get(...arguments) } }) const secondProxy = new Proxy(firstProxy, { get() { console.log("second") return Reflect.get(...arguments) } }) output second first bar

Agency issues

Proxy catcher and reflection method

get()
wait
That is, the operations that can be captured by the agent catcher correspond to the reflected API one by one, and the parameters also correspond to each other; At the same time, operations such as new delete, the methods above Object, and some assignment can correspond to the reflection API. Reflection can intercept their corresponding and operate

proxy pattern

Trace attribute access

const user = { name:'jake' } const proxy = new Proxy(user, { get(target, p, receiver) { console.log(`Get $`); return Reflect.get(...arguments) }, set(target, p, value, receiver) { console.log(`Set $ = $`); return Reflect.set(...arguments) } }) proxy.name; proxy.age = 22; In this way, what is done to what attribute and when are tracked at any time

Hide properties

The agent's internal code implementation is invisible to the outside, so it's easy to hide the properties on the target object

const hiddenProperties = ['foo','bar']; const targetObject = { foo: 1, bar: 2, baz: 3 } const proxy = new Proxy(targetObject,{ get(target,property) { if(hiddenProperties.includes(property)) { return undefined } else { return Reflect.get(...arguments) } }, has(target, p) { if(hiddenProperties.includes(p)) { return false; } else { return Reflect.has(...arguments) } } }) console.log(proxy.foo) console.log(proxy.bar) console.log(proxy.baz) console.log('foo' in proxy) console.log('bar' in proxy) console.log('baz' in proxy)

Attribute validation

All assignment operations will trigger the set() catcher, which can decide whether to allow or reject assignment according to the assigned value

const target = { onlyN: 0 } const proxy = new Proxy(target, { set(target, property, value, receiver) { if(typeof value !== 'number') { return false; } else }, get(target, p, receiver) { console.log('get') return Reflect.get(...arguments) } }) console.log(proxy.onlyN) proxy.onlyN = 1; console.log(proxy.onlyN)

Function and constructor parameter validation

Function and constructor parameters can be reviewed. For example, functions can only accept certain types of parameters

function median(...nums) { return nums.sort()[Math.floor(nums.length/2)] } const proxy = new Proxy(median, { apply(target, thisArg, argArray) { for(const arg of argArray) { if(typeof arg !== 'number') { throw 'NonNumber' } } return Reflect.apply(...arguments) } }) console.log(proxy(4,7,1)) console.log(proxy(4,'7',1));

Requires that arguments must be passed to the constructor

class User { constructor(id) { this.id_ = id; } } const proxy = new Proxy(User, { construct(target, argArray, newTarget) { if(argArray[0] === undefined) { throw 'user' } else { console.log('111') return Reflect.construct(...arguments) } } }) new proxy(1) new proxy()

Data binding and observable objects

Connect the parts that the runtime does not want to be associated with through the agent. For example, bind the proxy class to a global instance collection, so that all created instances are added to the collection

const userList = []; class User { constructor(name) { this.name_ = name; } } const proxy = new Proxy(User, { construct(target, argArray, newTarget) { const newUser = Reflect.construct(...arguments); userList.push(newUser) return newUser; } }) new proxy('john') new proxy('jacob') console.log(userList) output [ User { name_: 'john' }, User { name_: 'jacob' } ]

11 November 2021, 18:19 | Views: 8578

Add new comment

For adding a comment, please log in
or create account

0 comments