Reflection and agent
Recognize reflection and agency
Reflection and proxies are new language features in ECMAScript 6. Proxies give developers the ability to intercept and embed additional behavior into basic operations. In simple terms, intercepting operations on a proxy object that access properties, delete properties, add properties, and so on, and adding custom action behavior. Reflect is a built-in object that is a collection of methods that provide default behavior for the underlying action. It corresponds to the Proxy catcher one by one, and one of its main functions is to facilitate Proxy catcher calls.
Proxies and reflection are still fairly new, so this is pretty wordy. If you are familiar with the proxy feature, skip the basics and the application may be useful for you.
Here’s a simple proxy:
const target = {}
const handle = {
get: function(target,key, receiver){ // Define a trap here
console.log(target, key, receiver)
}
}
const proxy = new Proxy(target, handle);
console.log(target.a)
console.log(proxy.a)
Copy the code
Note that the proxy object does not have a Prototype. Then we can use reflection to optimize:
const target = {
id: 'foo'
}
const handle = {
get(){
return Reflect.get(... arguments) } }const proxy = new Proxy(target, handle)
console.log(proxy.id)
Copy the code
The proxy’s capture method corresponds to the reflection method. By default, the capture method can be written as follows:
const target = {
id: 'foo'
}
const proxy = new Proxy(target, Reflect)
console.log(Reflect)
console.log(proxy.id)
Copy the code
A normal Proxy object creates a Proxy object through new Proxy (), which does not cancel the Proxy. Proxy provides the Revocable method. A proxy created using this method can proactively disassociate the proxy object from the target object. Revocable agent:
const target = {
id: 'foo'
}
const handle = {
get(){
return Reflect.get(... arguments) } }const {proxy, revoke} = Proxy.revocable(target, handle)
console.log(proxy.id)
revoke()
console.log(proxy.id) // Uncaught TypeError: Cannot perform 'get' on a proxy that has been revoked
Copy the code
Proxy capture and reflection API
The agent has 13 traps (some call them trap functions), which correspond to 13 reflection methods. As follows:
- Base catcher
const proxy = new Proxy(target, {
/ * * *@param Target Target object *@param P propertyKey For example, ID *@param Receiver Proxy object *@returns {any return value} * /
get(target, p, receiver) {
return Reflect.get(... arguments) },/ * * * *@param Target Target object *@param p propertyKey
* @param value
* @param Receiver Proxy object *@returns {boolean}* /
set(target, p, value, receiver) {
return Reflect.set(... arguments) },deleteProperty(target, p) {
console.log(... arguments)return Reflect.deleteProperty(... arguments) } }); proxy.id proxy.id ='yosun'
delete proxy.id
Copy the code
- Prototype agent
const target = {id: 'yosun'}
const proxy = new Proxy(target, {
/ * * *@param target
* @returns {object}* /
getPrototypeOf(target) {
console.log(... arguments)return Reflect.getPrototypeOf(... arguments) },/ * * *@param target
* @param v
* @returns {boolean}* /
setPrototypeOf(target, v) {
return Reflect.setPrototypeOf(... arguments) } })Object.getPrototypeOf(proxy);
Object.setPrototypeOf(proxy, {});
Copy the code
- object
const target = {}
const proxy = new Proxy(target, {
isExtensible(target){
return Reflect.isExtensible(... arguments) },preventExtensions(target) {
return Reflect.preventExtensions(... arguments) },ownKeys(target) {
console.log(... arguments)return Reflect.ownKeys(... arguments) },/ * * *@param target
* @param p propertyKey
* @returns {boolean}* /
has(target, p) {
return Reflect.has(... arguments) },defineProperty(target, p, attributes) {
console.log(target, p, attributes)
return Reflect.defineProperty(... arguments) },getOwnPropertyDescriptor(target, p) {
console.log(... arguments)// return Reflect.getOwnPropertyDescriptor(... Arguments) // Use the default
return { configurable: true.enumerable: true.value: 'sun'}}})Object.isExtensible(proxy)
Object.preventExtensions(proxy)
'yosun' in target
Object.keys(proxy)
Object.defineProperty(proxy, 'id', {
value: 'yosun'
})
console.log(Object.getOwnPropertyDescriptor(proxy, 'id').value)
Copy the code
- function
const target = function () {}
const proxy = new Proxy(target, {
/ * * *@param target
* @param thisArg
* @param argArray
* @returns {*}* /
apply(target, thisArg, argArray) {
console.log(... arguments)return Reflect.apply(... arguments) },/ * * *@param target
* @param argArray
* @param newTarget
* @returns {any}* /
construct(target, argArray, newTarget) {
console.log(... arguments)return Reflect.construct(... arguments) } }) proxy(111)
new proxy(111)
Copy the code
application
To disable access to some attributes of an object, we can do this:
const hiddenPropertyKey = ['sex'.'age'];
const person = {
name: 'yosun'.age: '26'.sex: 'man'
}
const findHumanInfo = new Proxy(person, {
get(target, p, receiver) {
if(! hiddenPropertyKey.includes[p]){console.log('You have not yet had permission to access ~')
return undefined
}
return Reflect.get(... arguments) },has(target, p) {
if(! hiddenPropertyKey.includes[p]){console.log('You have not yet had permission to access ~')
return false
}
return Reflect.has(... arguments) } }) findHumanInfo.age// You do not have access yet
findHumanInfo.name // yosun
'age' in findHumanInfo // You do not have permission to access ~ return false
Copy the code
Our common web form validation is a rather troublesome problem, and the general code is not easy to integrate. Here is a common use of the set catcher:
const form = new Map(a);const validator = {
set(target, property, value, receiver) {
if(form.has(property)){
return form.get(property)(value)
}
return Reflect.set(... arguments) } } form.set('age', validateAge)
function validateAge(value){
if(typeofvalue ! = ="number" || Number.isNaN(value)){
throw new TypeError('Age must be a numeric type')}if(value<=0) {throw new TypeError('Age must be greater than zero')}return true
}
const formValidator = {
}
const proxy = new Proxy(formValidator, validator)
proxy.age = '十八'
Copy the code
Construct catcher application:
class SelfUser{
constructor(id) {
this.is = id
}
}
const User = new Proxy(SelfUser, {
construct(target, argArray, newTarget) {
if(! argArray[0]) {throw new Error("User ID cannot be empty")}else {
console.log('User created successfully')
return Reflect.construct(... arguments) } } })new User(1) // The user is created successfully
new User() // Uncaught Error: The user ID cannot be empty
Copy the code
TODO time reasons there are many unsorted —– (I have not understood the first do not share)
But let’s look at one code that I find interesting
const watchJsRun = (expectObject) = > {
if (typeof expectObject === 'object' || typeof expectObject === 'function') {return new Proxy(expectObject,Reflect.ownKeys(Reflect).reduce((handles, key) = > {
handles[key] = (. args) = > {
console.log(key, ... args)return Reflect[key](... args) }return handles
}, {}))
}
throw new Error('Cannot create proxy with a non-object as target or handler')}const arr = watchJsRun([])
// console.log(arr)
arr.push(1)
console.log('------------ splitter --------------')
let obj = watchJsRun({})
obj.id
console.log('------------ splitter --------------')
let fn = watchJsRun(function Person() {})new fn()
fn()
fn.prototype.doEveryThing = function () {
console.log('doEveryThing')}Copy the code
Take push as an example:
get Array(1)0: 1length: 1__proto__: Array(0) push Proxy
get Array(1)0: 1length: 1__proto__: Array(0) length Proxy
set Array(1) 0 1 Proxy
getOwnPropertyDescriptor Array(1) 0
defineProperty Array(1) 0 Object
set Array(1) length 1 Proxy
getOwnPropertyDescriptor Array(1) length
defineProperty Array(1) length Object
Copy the code
The above steps were performed. You can try ~ above demo is very key, far-reaching significance. Now that I’ve seen it, I’m sure I’ll try it. At this time of writing, it is already 6:07, 7 minutes after the end of work;) . I thought I’d make a point even if I didn’t finish. This friend, your praise is my motivation to study! Hahaha…
Common business code can hardly see the existence of proxy and reflection, proxy is derived from the proxy object, in line with the design concept of low coupling, high cohesion. Of course, don’t blindly use proxies, only when the object functionality becomes too complex and we need to limit access.
There are still a lot of learning, welcome to correct ~