最简单的proxy讲解,一遍就懂

Day 9

代理与反射

代理基础:

  • 代理是目标对象的抽象,能够当作是目标对象的替身,但彻底独立于目标对象,目标对象能够被直接操做,也能够经过代理来操做

建立空代理:

  • 最简单的代理是空代理,就是说除了做为一个抽象的目标对象,什么也不作,在代理对象是执行的全部操做都会无障碍的传播到目标对象,所以,任何使用目标对象的地方,均可以经过一样的方式使用与之关联的代理对象markdown

    例子1:函数

const target = { id: 'target' };
const handler = {}; const proxy = new Proxy(target, handler); // id属性会访问同一个值 console.log(target.id); // target  console.log(proxy.id); // target  // 给目标属性赋值会反映在两个对象上, 由于两个对象访问的是同一个值 target.id = 'foo'; console.log(target.id); // foo console.log(proxy.id); // foo  // 给代理属性赋值会反映在两个对象上,由于这个赋值会转移到目标对象 proxy.id = 'bar'; console.log(target.id); // bar console.log(proxy.id); // bar  // hasOwnProperty()方法在两个地方 都会应用到目标对象 console.log(target.hasOwnProperty('id')); // true  console.log(proxy.hasOwnProperty('id')); // true 复制代码

小结:这是最简单的一个空代理的案例,初看可能会不明因此,我当初看也很懵,可是不要着急,你如今只须要看懂,知道代理作了什么事情,在这个例子里,target是代理的目标,proxy是代理,代理的目标和代理属性共享,操做共享,包括方法也是共享的,可是代理并不等于代理目标,更倾向于操做代理时,代理把操做转发给了代理的目标,而后进行操做,目标拥有的,代理会拥有,代理拥有的,也会相应的传递给目标;oop

代码捕获器与反射方法:

  • 使用代理的目的 :是能够定义捕获器(trap),捕获器就是能够直接或间接在代理对象上调用,每次在代理对象上调用这些基本操做时, 代理能够在这些操做传播到目标对象以前先调用捕获器函数,从而拦 截并修改相应的行为。ui

    • 通俗讲就是,捕获器在代理对象被调用时,先执行,从而拦截而且修改相应的行为,就是相似加了一层if判断,或者说是弹框确认
  • handler :代理的处理对象,例子1中是一个空对象,多数状况下并非空对象,而是定义了一个或者多个捕获器(trap)去处理代理,若是没有定义,则和上例中的空对象同样,使用默认行为。this

  • set trap :经常使用的trap,触发条件是在设置属性值的时候触发,spa

  • Reflect.set: 将值分配给属性的函数。返回一个Boolean,若是更新成功,则返回true代理

    首先set trap接受4个参数,code

    • trapTarget - 接收的属性的对象,就是**代理的目标 **orm

    • key - 要写入的属性的对象

    • value- 写入属性的

    • receiver- 操做的对象,一般是代理

      例子2:用set trap验证一个属性的值是否为number

let target = {
 name: "target"  };   let proxy = new Proxy(target, {  //target,name,target,proxy;  set(trapTarget, key, value, receiver) {  console.log(`trapTarget is ${trapTarget}, key is ${key}, value is ${value}, receiver is ${receiver}`)  // 忽视存在的属性,以避免产生影响,不存在的属性才会进入判断  if (!trapTarget.hasOwnProperty(key)) {  //判断值是否为number  if (isNaN(value)) {  throw new TypeError("Property must be a number.");  }  }  // 添加到属性  return Reflect.set(trapTarget, key, value, receiver);  }  });  // 添加一个新的属性  proxy.count = 1;  console.log(proxy.count); // 1  console.log(target.count); // 1  // 赋值给存在target上的属性  proxy.name = "proxy";  console.log(proxy.name); // "proxy"  console.log(target.name); // "proxy"  // 新的属性值不是数字会抛出异常  proxy.anotherName = "proxy"; 复制代码
小结:这个例子打印出了4个参数的时刻变化,能够清晰的看到参数对应的值,能够发现,每次设置属性值的时候都会进行拦截判断,因此在获取时候,能够用get进行拦截判断,
复制代码
  • get trap:

    • get 是读取对象属性的时候用到的trap,他接受3个参数

    • trapTarget: 从哪一个对象读取的属性,就是target

    • key - 读取的key

    • receiver - 操做的对象,一般是代理(proxy)

      例子1:这是一个普通的get代理的按理

const handler = {
 get: function(obj, prop) {  return prop in obj ? obj[prop] : 37;  }  };   const p = new Proxy({}, handler);  p.a = 1;  p.b = undefined;   console.log(p.a, p.b); // 1, undefined  console.log('c' in p, p.c); // false, 37 复制代码
小结:p.a的时候,获取代理里面a的值通过get,返回了 a的值,p.b同样,而后c in p,由于p没有c这个属性,因此会返回false,p.c像p获取c属性,进入get,赋值为37,
复制代码
  • 再来看一个set 和get的综合例子

    例子3;

var p = {
 name:"chen",  work:function() {  console.log("wording...");  },  _age:18,  //监听获取name属性的事件  get name(){  return this._age;  },  //监听设置age属性的事件  set age(val) {  if (val<0 || val> 100) {//若是年龄大于100就抛出错误  throw new Error("invalid value")  }else{  this._age = val;  }  }  };  console.log(p.name);//输出18,由于这里触发了监听name属性的拦截,因此返回的age,  console.log(p._age);//这里的age没有获取拦截,因此输出原值  console.log(p._age =20);//输出20,由于这里进入设置拦截,知足条件,完成赋值  console.log(p._age =200);//报错,设置拦截进入,不知足条件,报错  console.log(p.name = 'yu')//输出 yu,由于name没有设置拦截,因此能够成功 复制代码

小结:看完这个,代理的基本知识及其原理相信你们都明白了,其实捕获器还有不少,列如has等等,可是基本原理都是这样,只要把握住参数分别表明什么,捕获器的触发条件,问题均可以迎刃而解了,但愿能够给你们带来帮助

本文使用 mdnice 排版

相关文章
相关标签/搜索