当前位置:网站首页>Proxy and reflection (II)

Proxy and reflection (II)

2022-06-12 02:11:00 Red blue purple

Proxy and reflection ( Two )

There are some useful functions that can be implemented using the proxy pattern .

Capture operation

By adding a corresponding catcher , You can capture it getsethas Wait for the operation , You can monitor when and where this object has been accessed , And can access 、 Do what you want to do before revision , And realize the original function again through reflection .

const user = {
    
  name: 'clz'
}


const proxy = new Proxy(user, {
    
  get(target, property, receiver) {
    
    console.log(` visit  ${
      property}`)
    return Reflect.get(...arguments)
  },
  set(target, property, value, receiver) {
    
    console.log(` Set up  ${
      property}=${
      value}`)
    return Reflect.set(...arguments)
  }
})

console.log(proxy.name)
proxy.age = 21

image-20220503205936504

Here's a little bit of attention : The operation through the proxy object will be captured , Operations that directly manipulate the target object are not captured .

const user = {
    
  name: 'clz'
}


const proxy = new Proxy(user, {
    
  get(target, property, receiver) {
    
    console.log(` visit  ${
      property}`)
    return Reflect.get(...arguments)
  }
})

console.log(proxy.name)
console.log(user.name)

image-20220503205922840

Hidden attribute

Because the internal implementation of the proxy is invisible to the external code , So it is easy to hide the attributes on the target object . We said that above , The original function needs to be realized through reflection , But we can also not realize the original function , Instead, it returns other values .

const user = {
    
  name: 'clz',
  age: 21
};


const proxy = new Proxy(user, {
    
  get(target, property, receiver) {
    
    if (property === 'name') {
    
      //  hide name attribute 
      return undefined;
    }
    return Reflect.get(...arguments)
  }
});

console.log(user)
console.log(user.name)
console.log(user.age)

console.log('%c%s', 'font-size:24px;color:red', '=================')

console.log(proxy)
console.log(proxy.name)
console.log(proxy.age)

image-20220503210140040

From above , We can know , Direct access to the target object 、 Target object properties and access to proxy objects can achieve the same results . however , Access... Through a proxy name Property will get undefined, Because we have hidden attributes in the capture operation .

verification

Attribute validation

Because all assignment operations will trigger set Catcher , Therefore, you can decide whether to allow or reject the assignment according to the assigned value , Not verified , direct return false The assignment can be rejected .

const user = {
    
  name: 'clz',
  age: 21
};


const proxy = new Proxy(user, {
    
  set(target, property, value) {
    
    if (typeof value !== 'number') {
    
      console.log(' No number type , Reject assignment ')
      return false;
    } else {
    
      return Reflect.set(...arguments);
    }
  }
});

proxy.age = 999;
console.log(proxy.age);

proxy.age = '111';
console.log(proxy.age);

image-20220503211445808

When we return false when , That is, it fails to pass the verification , You can avoid the implementation of the original behavior ,

Function parameter validation

Similar to validating object properties , You can also review the parameters of a function .

First , Functions can also use proxies .apply The catcher is called when the function is called .

function fn() {
     }

const proxy = new Proxy(fn, {
    
    apply() {
    
        console.log(' Call function ')
    }
});

proxy(1, 2, 3, 4, 5)

So we should apply Operation verification in the catcher .

function mysort(...nums) {
    
  return nums.sort((a, b) => a - b);
}


//  stay `apply` Parameter validation in the catcher 
const proxy = new Proxy(mysort, {
    
  apply(target, thisArg, argumentsList) {
    
    // target:  Target audience 
    // thisArg:  When calling a function this Parameters 
    // argumentsList:  List of parameters when calling a function 

    for (const arg of argumentsList) {
    
      if (typeof arg !== 'number') {
    
        throw ' Function arguments must be number';
      }
    }

    return Reflect.apply(...arguments);
  }
});

let fin = proxy(2, 1, 6, 3, 4, 3);
console.log(fin);

fin = proxy(2, 1, 'hello', 3, 4, 3);
console.log(fin);

The same goes for constructors , Only the constructor is passed through constructor Capture to implement the proxy .

function Person(name) {
    
  this.name = name
}

const proxy = new Proxy(Person, {
    
  construct() {
    
    console.log(123)
    return Reflect.construct(...arguments)
  }
});

const p = new proxy('clz')
console.log(p)

Data binding

Through the agent, the irrelevant parts of the original operation can be linked together .

Example : Bind the proxied class to a global collection of instances , Add all the created instances to this collection .`

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('clz')
new proxy('czh')

console.log(userList)

Event distributor

Before we start , Let's start with a little question .

    const nums = []

    const proxy = new Proxy(nums, {
    
      set(target, property, value, receiver) {
    
        console.log('setting')

        return Reflect.set(...arguments)
      }
    })

    proxy.push(1)

The above code will be printed twice setting.

Why is that ?

Let's print out the attributes of each round of modification , Look at the .

const nums = []

const proxy = new Proxy(nums, {
    
  set(target, property, value, receiver) {
    
    console.log('setting')

    console.log(property)

    return Reflect.set(...arguments)
  }
})

proxy.push(1)

image-20220503234749114

We can find out , The first is 0, The second, length. in other words ,push It is actually divided into two stages , In the first round, modify the array first , The second round is to modify the array length , So it prints two rounds .( There is no authoritative explanation , The conclusion of the practical test , There are questions to comment on )

Back to the point : You can bind a collection to an event distributor , Each time a new instance is inserted , Will send messages .

const nums = []

function emit(newValue) {
    
  console.log(' There's new data , The new data is ', newValue)
}


const proxy = new Proxy(nums, {
    
  set(target, property, value, receiver) {
    
    const result = Reflect.set(...arguments)
    // Reflect.set return boolean value , This value indicates whether the property has been successfully set 

    if (result) {
    
      //  If it is set successfully , Call the event dispatch function , Pass the newly inserted value as a parameter 

      emit(Reflect.get(target, property, receiver))
    }

    return result
  }
})

proxy.push(111)
proxy.push(222)
console.log(proxy)

image-20220503235521715

You can find it here , We push Two pieces of data , But it will trigger the event distributor 4 Time , Why is that ?

This is what was said in this section ,push It is actually divided into two stages , In the first round, modify the array first , The second round is to modify the array length .

therefore , We should not just judge whether it has been successfully set up , You should also judge whether the attribute is length.

if (result && property !== 'length') {
    
  //  If it is set successfully , Call the event dispatch function , Pass the newly inserted value as a parameter 

  emit(Reflect.get(target, property, receiver))
}

image-20220504000010868

原网站

版权声明
本文为[Red blue purple]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/163/202206120206540965.html