步遥——PROXY

PROXY (代理器)
用处:
修改某些操作的默认行为,等同于在语言层面做出修改,属于一种"元编程",即对编程语言进行的编程。
就是在目标对象之前架设一层拦截,外界对该对象的访问,都必须通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。

语法:

let proxy = new Proxy(target,handler) //生成proxy实例,target参数表示所要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为

handler是一个配置对象,对于每一个被代理的操作,需要提供一个对应的处理函数,该函数将拦截对应的操作。

例子:

let person = {name:'张三'}
let proxy = new Proxy(person,{
    get:function(target,propKey){//target指向person这个对象,propKey是指target指向的对象的属性
      //get方法,修改对象object获取属性的逻辑
    }
})

上面代码中的配置对象中有一个get方法,用来拦截对目标对象属性的访问请求。get方法中的两个参数,分别是目标对象和所要访问的属性,

对目标对象设置后拦截器之后,对产生的实例进行操作,对原目标对象操作就不起作用。
如果没有设置任何拦截,就等同于直接通向原对象。
proxy实例也可以作为其他对象的原型对象。
同一个拦截器可以设置多个操作。
对于可以设置,但没有设置拦截操作,则直接落在目标对象上,按照原先的方式产生结果。

let prox = new Proxy({z:3},{
get:function(target,propKey){
    console.log(target,propKey)
    if(propKey === 'z'){
      return target[propKey]
    }
    return 35
}})
prox.z // {z:3} 'z'
prox.a // {z:3} 'a'

拦截器中可以设置的handler中的操作有13种:
get(target,propKey,receiver) :拦截对象属性的读取,

set(target,propKey,value,receiver) :拦截对象属性的设置

has(target,propKey) : 拦截propKey in proxy的操作,返回一个布尔值

deleteProperty(target,propKey):拦截delete proxy[propKey]的操作,返回一个布尔值

ownKeys(target): 拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for...in循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而Object.keys()的返回结果仅包括目标对象自身的可遍历属性。

getOwnPropertyDescriptor(target,propKey):拦截Object.getOwnPropertyDescriptor(proxy,propKey),返回属性的描述对象。

defineProperty(target,propKey,propDesc) :拦截 Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs),返回一个布尔值。

preventExtensions(target):拦截Object.preventExtensions(proxy),返回一个布尔值。

getPrototypeOf(target):拦截Object.getPrototypeOf(proxy),返回一个对象

isExtensible(target):拦截Object.isExtensible(proxy),返回一个布尔值。

setPrototypeOf(target, proto):拦截Object.setPrototypeOf(proxy, proto),返回一个布尔值。

如果目标对象是函数,那么还有两种额外操作可以拦截。
apply(target, object, args):拦截 Proxy 实例作为函数调用的操作,比如proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)。当实例作为函数调用时,就会被apply方法拦截。
construct(target, args):拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(...args)。

实例:get
使用proxy,将读取属性的操作get,转变为执行某个函数,从而实现属性的链式操作:

var pipe = function (value) {
  var funcStack = [];
  var oproxy = new Proxy({} , {
    get : function (pipeObject, fnName) {
      if (fnName === 'get') {
        return funcStack.reduce(function (val, fn) {
          return fn(val);
        },value);
      }
      funcStack.push(window[fnName]);
      return oproxy;
    }
  });

  return oproxy;}

var double = n => n * 2;var pow    = n => n * n;var reverseInt = n => n.toString().split("").reverse().join("") | 0;

pipe(3).double.pow.reverseInt.get; // 63

实例:set
设置存值函数set,任何不符合要求的age属性赋值,都会抛出一个错误。这是数据验证的一种方法。

let validator = {
  set: function(obj, prop, value) {
    if (prop === 'age') {
      if (!Number.isInteger(value)) {
        throw new TypeError('The age is not an integer');
      }
      if (value > 200) {
        throw new RangeError('The age seems invalid');
      }
    }
    // 对于满足条件的 age 属性以及其他属性,直接保存
    obj[prop] = value;
  }};

let person = new Proxy({}, validator);

person.age = 100;

person.age // 100
person.age = 'young' // 报错
person.age = 300 // 报错

你可能感兴趣的:(步遥——PROXY)