Agent based

Proxies are something that ES6 provides developers with the ability to intercept low-level operations on objects and add additional behaviors on top of them. It acts as a gatekeeper, stopping visitors (low-level operations) for questioning (developer logic). If you can, open the door and get in. If you can’t, beat it and throw it out

To create the agent

const handler = {}
const target = {
  id: 'target'
}
const proxy = new Proxy(target, handler)
Copy the code

A Proxy is a Proxy object created by the Proxy constructor, which takes two arguments

  • Target Target object (object to operate on)
  • Handler handler object (collection object of the catcher API fired after interception)

The target object can be called directly, or we can call it through a proxy object. The final operation result is also reflected in the target object

const handler = {}
const target = {
  id: 'target'
}
const proxy = new Proxy(target, handler)
proxy.id = 'proxy'
// Modifying the property value of the proxy object is also reflected in the target object
console.log(target) // { id: "proxy" }
console.log(proxy) // { id: 'proxy' }
// The target object is also reflected in the proxy object
// Because it refers to the same object
traget.name = 'yu'
console.log(target) // { id: "proxy", name: 'yu' }
console.log(proxy) // { id: "proxy", name: 'yu' }
Copy the code

Note: The prototype of the Proxy constructor is undefined

capture

The ability of the agent to intercept low-level operations and perform additional operations is achieved through the catcher. A catcher is defined within a rehandler object, and a handler object can define multiple catcher methods. Each trap corresponds to a basic operation.

  • For example, an operation to get an object property corresponds to a GET trap method
const handler = {
  get(target, property, proxy) {
  	console.log('Triggered get method')
    return target[property]
  }
}
const target = {
  id: 'target'
}
const proxy = new Proxy(target, handler)
proxy.id // 'trigger get method'
Copy the code

These traps fire only on proxy objects, not directly on target objects

The catcher methods have corresponding parameters through which new behavior logic can be reconstructed. For example, the get method takes three arguments

  • Target Target object
  • Property Indicates the property to be queried
  • Proxy Proxy object

An agent contains 13 catcher methods that can reconstruct the new behavior. But there’s also a primitive behavior that’s supposed to have this operation, but some primitive behaviors are very duplicative, and we might have trouble doing it manually. So ES6 gives developers a reflection API that gives us basic raw behavior that we don’t have to write.

Reflect

A reflection Object is an Object with 13 methods, equivalent to a subset of Object. But it turns some of Object’s imperative operations into functions.

  • The in operator, for example, corresponds to reflect.has
  • For example, the delete operator, which corresponds to reflect.deleteProperty

Reflecting objects also has the benefit of modifying the returns of some Object methods to make them more reasonable. For example, Object.defineProperty(obj, name, desc) throws an error if the attribute cannot be defined, while Reflect.defineProperty(obj, name, desc) returns false

The best use of the Reflect object is that it corresponds to the methods of the proxy proxy object’s catcher and can be used in conjunction with the proxy proxy object

const target = {
  id: 'target'
}
const handler = {
  get(target, property, handler) {
      let a = ' '
      if (property === 'id') {
          a = '!!!!!! '
      }
      return Reflect.get(... arguments) + a } }const proxy = new Proxy(target, handler)
console.log(proxy.id) // target!!!
Copy the code

Capture the API

get()

The get trap is fired when the property is retrieved, and the corresponding reflection API is reflect.get

The return value of the GET method is unlimited

Interception operation

  • proxy.property
  • proxy[property]
  • Object.create(proxy)[property]
  • Reflect.get(proxy, property, receiver)

parameter

  • Target Target object
  • Property Indicates the property to be queried
  • Proxy Proxy object
const myTarget = {}; 
const proxy = new Proxy(myTarget, { 
 get(target, property, receiver) { 
 console.log('get()'); 
 return Reflect.get(... arguments) } }); proxy.foo;// get()
Copy the code

set()

The set trap is triggered by setting the property, and the corresponding reflection API is reflect.set

The return value of the set method returns true, indicating success; Returning false indicates failure, and TypeError is raised in strict mode

Interceptor operations

  • proxy.property = value
  • proxy[property] = value
  • Object.create(proxy)[property] = value
  • Reflect.set(proxy, property, value, receiver)

parameter

  • Target: indicates the target object.
  • Property: String key property on the referenced target object.
  • Value: The value to be assigned to the attribute.
  • Receiver: The object that receives the initial assignment.
const myTarget = {}; 
const proxy = new Proxy(myTarget, { 
 set(target, property, value, receiver) { 
 console.log('set()'); 
 return Reflect.set(... arguments) } }); proxy.foo ='bar'; 
// set()
Copy the code

has()

The HAS trap is triggered by using the in operator, and the corresponding reflection API is reflect.has ().

The HAS method must return a Boolean value indicating whether the attribute exists. Returns non-Boolean values are converted to booleans

Interceptor operations

  • property in proxy
  • property in Object.create(proxy)
  • with(proxy) {(property); }
  • Reflect.has(proxy, property)

parameter

  • Target: indicates the target object.
  • Property: String key property on the referenced target object.
const myTarget = {}; 
const proxy = new Proxy(myTarget, { 
 has(target, property) { 
 console.log('has()'); 
 return Reflect.has(... arguments) } });'foo' in proxy; 
// has()
Copy the code

defineProperty()

The defineProperty catcher is triggered by using object.defineProperty () and the corresponding reflection API is reflect.defineProperty ().

The defineProperty method must return a Boolean value indicating whether the attribute was successfully defined. Returns non-Boolean values are converted to booleans.

Interceptor operations

  • Object.defineProperty(proxy, property, descriptor)
  • Reflect.defineProperty(proxy, property, descriptor)

parameter

  • Target: indicates the target object.
  • Property: String key property on the referenced target object.
  • Descriptor: Contains optional enumerable, 64x, writable, value, get, and set definitions.
const myTarget = {}; 
const proxy = new Proxy(myTarget, { 
 defineProperty(target, property, descriptor) { 
 console.log('defineProperty()'); 
 return Reflect.defineProperty(... arguments) } });Object.defineProperty(proxy, 'foo', { value: 'bar' }); 
// defineProperty()
Copy the code

getOwnPropertyDescriptor()

GetOwnPropertyDescriptor capture is through the use of the Object. The getOwnPropertyDescriptor triggered (), the corresponding reflection API is Reflect getOwnPropertyDescriptor ()

The getOwnPropertyDescriptor method must return an object, or undefined if the property does not exist.

Interceptor operations

  • Object.getOwnPropertyDescriptor(proxy, property)
  • Reflect.getOwnPropertyDescriptor(proxy, property)

parameter

  • Target: indicates the target object.
  • Property: String key property on the referenced target object.
const myTarget = {}; 
const proxy = new Proxy(myTarget, { 
 getOwnPropertyDescriptor(target, property) { 
 console.log('getOwnPropertyDescriptor()'); 
 return Reflect.getOwnPropertyDescriptor(... arguments) } });Object.getOwnPropertyDescriptor(proxy, 'foo'); 
// getOwnPropertyDescriptor()
Copy the code

deleteProperty()

The deleteProperty capture is triggered by the use of the DELETE operator and the corresponding reflection API is reflect.deleteProperty ()

The deleteProperty method must return a Boolean value indicating whether the property was successfully deleted. Returns non-Boolean values are converted to booleans.

Interceptor operations

  • delete proxy.property
  • delete proxy[property]
  • Reflect.deleteProperty(proxy, property)

parameter

  • Target: indicates the target object.
  • Property: String key property on the referenced target object.
const myTarget = {}; 
const proxy = new Proxy(myTarget, { 
 deleteProperty(target, property) { 
 console.log('deleteProperty()'); 
 return Reflect.deleteProperty(... arguments) } });delete proxy.foo 
// deleteProperty()
Copy the code

ownKeys()

The ownKeys trap is triggered by object.keys () and similar methods. The corresponding reflection API method is reflect.ownkeys ()

Interceptor operations

  • Object.getOwnPropertyNames(proxy)
  • Object.getOwnPropertySymbols(proxy)
  • Object.keys(proxy)
  • Reflect.ownKeys(proxy)

parameter

  • Target: indicates the target object.
const myTarget = {}; 
const proxy = new Proxy(myTarget, { 
 ownKeys(target) { 
 console.log('ownKeys()'); 
 return Reflect.ownKeys(... arguments) } });Object.keys(proxy); 
// ownKeys()
Copy the code

getPrototypeOf()

The getPrototypeOf capture is triggered by retrieving the prototype Object in Object.getPrototypeof (), corresponding to reflect.getPrototypeof ().

GetPrototypeOf () must return an object or NULL.

Interceptor operations

  • Object.getPrototypeOf(proxy)
  • Reflect.getPrototypeOf(proxy)
  • proxy.proto
  • Object.prototype.isPrototypeOf(proxy)
  • proxy instanceof Object

parameter

  • Target: indicates the target object.
const myTarget = {}; 
const proxy = new Proxy(myTarget, { 
 getPrototypeOf(target) { 
 console.log('getPrototypeOf()'); 
 return Reflect.getPrototypeOf(... arguments) } });Object.getPrototypeOf(proxy); 
// getPrototypeOf()
Copy the code

setPrototypeOf()

The setPrototypeOf capture is triggered in the prototype Object using object.setPrototypeof (), corresponding to reflect.setprototypeof ().

The setPrototypeOf method must return a Boolean value indicating whether the prototype assignment was successful. Returns non-Boolean values are converted to booleans

Interceptor operations

  • Object.setPrototypeOf(proxy)
  • Reflect.setPrototypeOf(proxy)

parameter

  • Target: indicates the target object.
  • Prototype: Target substitute prototype. Null if it is a top-level prototype.
const myTarget = {}; 
const proxy = new Proxy(myTarget, { 
 setPrototypeOf(target, prototype) { 
 console.log('setPrototypeOf()'); 
 return Reflect.setPrototypeOf(... arguments) } });Object.setPrototypeOf(proxy, Object); 
// setPrototypeOf()
Copy the code

isExtensible

IsExtensible capture is called through Object.isextensible (). The corresponding reflection API method is reflect.isextensible ()

IsExtensible () must return a Boolean value indicating whether target isExtensible. Returns non-Boolean values are converted to booleans.

Interceptor operations

  • Object.isExtensible(proxy)
  • Reflect.isExtensible(proxy)

parameter

  • Target: indicates the target object.
const myTarget = {}; 
const proxy = new Proxy(myTarget, { 
 isExtensible(target) { 
 console.log('isExtensible()');
 return Reflect.isExtensible(... arguments) } });Object.isExtensible(proxy); 
// isExtensible()
Copy the code

preventExtensions

The preventExtensions catcher is called in object.preventExtensions (). The corresponding reflection API method to Reflect preventExtensions ().

PreventExtensions () must return a Boolean value indicating whether target is already unextensible. Returns non-Boolean values are converted to booleans

Interceptor operations

  • Object.preventExtensions(proxy)
  • Reflect.preventExtensions(proxy)

parameter

  • Target: indicates the target object.
const myTarget = {}; 
const proxy = new Proxy(myTarget, { 
 preventExtensions(target) { 
 console.log('preventExtensions()'); 
 return Reflect.preventExtensions(... arguments) } });Object.preventExtensions(proxy); 
// preventExtensions()
Copy the code

apply

The Apply catcher is called when the function is called. The corresponding reflection API method is reflect.apply ()

Interceptor operations

  • proxy(… argumentsList)
  • Function.prototype.apply(thisArg, argumentsList)
  • Function.prototype.call(thisArg, … argumentsList)
  • Reflect.apply(target, thisArgument, argumentsList)

parameter

  • Target: indicates the target object.
  • ThisArg: this argument when the function is called.
  • ArgumentsList: The list of arguments when a function is called
const myTarget = () = > {}; 
const proxy = new Proxy(myTarget, { 
 apply(target, thisArg, ... argumentsList) { 
 console.log('apply()'); 
 return Reflect.apply(... arguments) } }); proxy();// apply()
Copy the code

construct

The construct() trap is called in the new operator. The corresponding reflection API method is reflect.construct ()

Construct () must return an object

Interceptor operations

  • new proxy(… argumentsList)
  • Reflect.construct(target, argumentsList, newTarget)

parameter

  • Target: Target constructor.
  • ArgumentsList: The list of arguments passed to the target constructor.
  • NewTarget: the constructor originally called.
const myTarget = function() {}; 
const proxy = new Proxy(myTarget, { 
 construct(target, argumentsList, newTarget) { 
 console.log('construct()'); 
 return Reflect.construct(... arguments) } });new proxy; 
// construct()
Copy the code