Recently, the company is organizing the front-end team to learn JavaScript advanced programming (Fourth Edition). After reading Chapter 9 in these two days, the following is a simplified version of the study notes:
Key points of this chapter:
- Proxy means proxy. You can create a proxy object for the target object targetObj through the constructor proxy
- When performing operations on the proxy object, you will use the methods in the handler to perform operations on the source object
- The agent can capture 13 different basic APIs, and multiple capture methods can be defined in the handler
- It is a global Reflect object. All captured methods have corresponding Reflect api methods. It has the same name and behavior as the method intercepted by the catcher.
- The Reflect api is not limited to the capture handler, but can also be used to process ordinary objects
- Most of the reflect APIs have corresponding methods on the Object
- With Reflect, you can easily write the catcher
- Several applications of agent mode
proxy
what? (what is Proxy?)
Proxy means proxy. You can create a proxy object for the target object targetObj through the constructor proxy.
const proxyObj = new Proxy(targetObj, handlerObj)
You can create a proxy for the object obj.
why? (why use Proxy?)
When performing some object operations on the proxy object, the method defined by the handlerObj object in the proxy will be executed first.
For example:
get( ) // Get object properties set( ) // Add attributes to objects
how? (how to use Proxy?)
When operating on the proxy object, the method in the handler will be used
When performing operations on the source object, the methods in the handler will not be used
const target = {foo: "bar"} const handler = { get(target, prop, receiver){ // get() is a catcher whose parameters respectively represent: target object, target attribute and proxy object. The input parameters of each catcher are different. return "handle override" } } const proxyObj = new Proxy(target,handler) console.log(proxyObj.foo) // "handle override", execute handler console.log(target.foo) // "bar", no handler executed
Reflect
what? (what is Reflect?)
It is a global Reflect object. All captured methods have corresponding Reflect api methods. It has the same name and behavior as the method intercepted by the catcher.
The Reflect api is not limited to the capture handler handler
Most of the reflect APIs have corresponding methods on the Object.
why? (why use Reflect?)
With Reflect, you can easily write the catcher.
Take an example:
const target = {foo: "bar"} const handler = { get(target, prop, receiver){ return Reflect.get(...arguments) } } const proxyObj = new Proxy(target,handler)
The Reflect api provides some status tags.
Reflect.set() ,Reflect.defineProperty() returns a Boolean value.
The Reflect api replaces operators with first-class functions. Reflect.has( )
const obj = {name: "cc"} const target = Object.create(obj) target.age = 12 if(Reflect.has(target, "name")) { // The effect of the in operator of the pro test and the object is the same, and the attributes on the prototype chain of the object can be obtained console.log("wow, I have!") }
how? (how to use Reflect?)
Above, it can be used when writing the catcher. It can also be used on the object by using its return value
Proxy catcher and corresponding reflection method
The agent can capture the different base APIs in 13.
get() get property
set() sets the property value
When has() object performs in operation
defineProperty( )
getOwnPropertyDescriptor()
deleteProperty()
ownKeys()
getPrototypeOf()
setPropotypeOf()
isExtensible()
preentExtensions()
apply()
construct()
Several applications of agent mode
- Trace attribute access
By capturing operations such as get, set and has, you can know when object properties are accessed and queried.
- Hide attributes
- Attribute validation
Write the catcher in set() to verify whether the assignment operation of the object is legal
example:
setObjDataEmpty = (paramObj) => { const proxy = new Proxy(paramObj, { set(target, prop) { const oldVal = target[prop] if(typeof oldVal === "string") { // String, direct assignment return Reflect.set(...arguments) }else if(Array.isArray(oldVal)){ return Reflect.set(target, prop, []) // Array, empty }else{ return false // Neither, assignment failed } } }) Object.keys(proxy).forEach(key => { proxy[key] = "" }) return proxy }
- Parameter validation of functions and constructors
consructor = () => { class SetId { constructor(id) { this.id = id } } const pSetId = new Proxy(SetId, { construct(target, argumentList) { if(argumentList[0] === undefined) { throw("oh, you must put id!") }else{ return Reflect.construct(...arguments) } } }) const id1 = new pSetId("1") console.log(id1) // {id: '1'} const id2 = new pSetId() // Uncaught oh, you must put id! console.log(id2) }
- Data binding and observable objects
const userList = []; class User { constructor(name) { this.name = name; } } const proxy = new Proxy(User, { construct() { const newUser = Reflect.construct(...arguments); userList.push(newUser); return newUser; } }); new proxy('John'); new proxy('Jacob'); new proxy('Jingleheimerschmidt'); console.log(userList);