当前位置: 首页 / 技术干货 / 正文
vue3.0中使用的proxy,不了解怎么涨薪

2023-02-02

   proxy 对象

  前言

  现在vue3.0虽然没有大规模使用在项目中,但面试的时候问的可一点也不少.特别是vue中双向数据绑定,几乎必问.但vue2.0和vue3.0的数据绑定还是不一样的....

  一、vue2.x的双向数据绑定

  · 在Vue2.x中,双向数据绑定是通过Object.definePropert实现的.

  · 用get,set方法中通过发布订阅者模式来实现的数据响应。

  · 但它只能监听存在的属性,对于新增或删除的便无能无力.

  · 同时数组的改变他也是没有办法监听的.

  二、proxy的使用

  1.proxy是个什么玩意

  · ES6中新增的代理反射,可以然让我们拦截一些操作,且添加其它的能力.

  · 简单说,我们对某个对象设置拦截器后,它的一些操作就能被我们捕获到,如此我们可以按照需求对默认的行为进行修改或者其它操作.

  · 类似于常见的钩子函数,发生某个行为时,触发某个钩子函数.

  2.基本形式

  语法

  const proxy = new Proxy(target, handler)

  · target: 要监听的对象,可以是一个对象,数组,函数等等

  · handler: 是对象,里面包含了可以监听target的方法.

  · proxy为返回的新对象, 为了能够触发handler里面的函数,必须要使用返回值去进行其他操作,比如修改值.handler里面的方法可以有以下这十三个,每一个都对应的一种或多种针对proxy代理对象的操作行为

  支持的写法

  Proxy提供了十三种拦截对象操作的方法,这里只介绍几个vue3中常用到的,更多的请参考MDN

  1. handler.get()当通过proxy去读取对象里面的属性的时候,会进入到get钩子函数里面.

  2. handler.set当通过proxy去为对象设置修改属性的时候,会进入到set钩子函数里面

  3. handler.has当使用in判断属性是否在proxy代理对象里面时,会触发has,比如

  const obj = {

  name: '小甜甜'

  }

  console.log('name' in obj)

  3. handler.apply当proxy监听的是一个函数的时候,当调用这个函数时,会进入apply钩子函数

  4. handler.construct当使用new操作符的时候,会进入construct这个钩子函数

  5. handler.defineProperty当使用Object.defineProperty去修改属性修饰符的时候,会进入这个钩子函数

  3.常用API

  Reflect 对象

  const target = {

  id:'target'

  }

  const handler ={

  // 捕获器在处理程序时,以方法名为键

  get(){

  return 'handle override';

  }

  }

  const proxy = new Proxy(target,handler);

  console.log(target.id); // target

  console.log(proxy.id); // handle override

  · 以上方法中,是基于参数,重建操作,可不是所有的捕获器行为都像get这么简单

  · 我们可以通过Reflect对象上的同名方法,来继续当前的默认行为.

  const target = {

  id:'target'

  }

  const handler ={

  // 捕获器在处理程序时,以方法名为键

  get(){

  //Reflect上的同名方法 继续原来的操作

  return Reflect.get(...arguments);

  }

  }

  const proxy = new Proxy(target,handler);

  console.log(target.id); // target

  console.log(proxy.id); // target

  · 操作符的替代

  Reflect.get() 替代对象属性访问操作符号.

  Reflect.set() 替代= 赋值操作符,返回 bool值

  Reflect.has() 替代in操作符或者with()

  Reflect.deleteProperty() 替代delete操作符

  Reflect.constructor() 替代new操作符

  代理捕获器和反射方法

  对于代理对象上的任何一种操作,只会有一个捕获处理器被调用.

  1. get() 在获取属性值,操作时调用.对应反射API为Reflect.get()

  const target = {

  id:'target'

  }

  const handler ={

  // 捕获器在处理程序时,以方法名为键

  get(){

  console.log('get()被调用');

  return Reflect.get(...arguments);

  }

  }

  const proxy = new Proxy(target,handler);

  proxy.foo; // get()被调用

  2. set() 捕获器会在设置属性时调用,对应反射API为Reflect.set()

  const target = {

  id:'target'

  }

  const handler ={

  // 捕获器在处理程序时,以方法名为键

  set(target,property,value,receiver){

  console.log('set()被调用');

  return Reflect.set(...arguments);

  }

  }

  const proxy = new Proxy(target,handler);

  proxy.foo = 'bar';

  //target 为目标对象

  // property 为属性

  // value 为属性值

  // receiver 接收最初赋值对象

  · apply() 会在调用函数时被调用,对应的反射api为Reflect.apply()

  const fn = ()=>{

  }

  const proxy = new Proxy(fn,{

  apply(target,thisArg,...argumentsList){

  console.log('apply()');

  return Reflect.apply(...arguments)

  }

  })

  proxy(); // apply

  · construct() 会在new操作符时被调用;

  const fn = function(){

  }

  const proxy = new Proxy(fn,{

  // target必须为构造函数

  construct(target,argumentList,newTarget){

  console.log('construct');

  return Reflect.construct(...arguments)

  }

  })

  new proxy();

  4.使用场景

  a. 隐藏属性,

  将目标对象上的属性进行隐藏.

  const hiddenProperites = ['foo','bar'];

  const tarObject = {

  foo:1,

  bar:2,

  baz:3

  };

  const proxy = new Proxy(tarObject,{

  get(target,property){

  if(hiddenProperites.includes(property)){

  return undefined;

  }else{

  return Reflect.get(...arguments)

  }

  },

  has(target,property){

  if(hiddenProperites.includes(property)){

  return false;

  }else{

  return Reflect.has(...arguments)

  }

  }

  });

  console.log(proxy.foo); // undefined

  console.log(proxy.baz); // 3

  console.log('foo' in proxy); // false

  console.log('baz' in proxy); // true

  b 属性验证

  所有的赋值操作都会触发set,我们可以所赋的值决定是允许还是拒绝.

  const target = {

  num:0

  }

  const proxy = new Proxy(target,{

  set(target,property,value){

  // 是number 类型才允许赋值

  if(typeof value !== 'number'){

  return false;

  }else{

  return Reflect.set(...arguments)

  }

  }

  });

  proxy.num = 2;

  console.log(proxy); // Proxy {num: 2}

  proxy.num = 'abc';

  console.log(proxy); // Proxy {num: 2}

  c 构造函数必须传参

  和保护和验证对象的属性相似,我们也可以对构造函数的参数进行审查.

  // 类必须传递参数

  class User{

  constructor(id) {

  this._id = id;

  }

  }

  const proxy = new Proxy(User,{

  construct(target,argumentsList,newTarget){

  if(argumentsList[0]===undefined){

  throw '必须传递参数'

  }else{

  return Reflect.construct(...arguments);

  }

  }

  })

  new proxy(); // Uncaught 必须传递参数

  d 对象的可观察

  向数组中每插入一个值,emit方法就会收到消息

  const userList = [];

  // 接收传递的值

  function emit(newValue){

  console.log(newValue);

  }

  const proxy = new Proxy(userList,{

  set(target,property,value,receiver){

  const result = Reflect.set(...arguments)

  if(result){

  // 设置值时,调用emit方法

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

  }

  return result;

  }

  });

  proxy.push('小甜甜');

  三、总结

  · 代理是由你创建的特殊对象,它封装另一个普通对象,或者谁挡在普通对象前面.

  · 可以在代理对象上注册特殊的处理函数,代理商执行各种操作时就会调用这个程序.

  · 这些程序除了把操作转发给原始目标/被封对象外,还会执行其它额外操作.

分享: 更多

上一篇:Sitespeed使用教程

下一篇:Hive的分区表

好程序员公众号

  • · 剖析行业发展趋势
  • · 汇聚企业项目源码

好程序员开班动态

More+
  • HTML5大前端 <高端班>

    开班时间:2021-04-12(深圳)

    开班盛况

    开班时间:2021-05-17(北京)

    开班盛况
  • 大数据+人工智能 <高端班>

    开班时间:2021-03-22(杭州)

    开班盛况

    开班时间:2021-04-26(北京)

    开班盛况
  • JavaEE分布式开发 <高端班>

    开班时间:2021-05-10(北京)

    开班盛况

    开班时间:2021-02-22(北京)

    开班盛况
  • Python人工智能+数据分析 <高端班>

    开班时间:2021-07-12(北京)

    预约报名

    开班时间:2020-09-21(上海)

    开班盛况
  • 云计算开发 <高端班>

    开班时间:2021-07-12(北京)

    预约报名

    开班时间:2019-07-22(北京)

    开班盛况
IT培训IT培训
在线咨询
IT培训IT培训
试听
IT培训IT培训
入学教程
IT培训IT培训
立即报名
IT培训

Copyright 2011-2023 北京千锋互联科技有限公司 .All Right 京ICP备12003911号-5 京公网安备 11010802035720号