都知道vue3响应式是Proxy实现的,进来把proxy与Reflect吃透

前言

众所周知,vue2.x版本实现双向绑定是利用的Object.defineproperty实现的,它有不少的缺点,例如无法检测到对象属性的新增或删除,无非监听数组变化等。所以在vue3版本,对其进行了改进,利用es6的新语法proxy改写了响应式原理。

那么你知道proxy到底是什么吗?另外Reflect你知道吗,它也是es6对操作对象设计的API。一起来看看吧

另外,本期博客参与了新星计划】,还请大家三连支持一下🌟🌟🌟感谢感谢💓💓💓


目录

前言

目录

Proxy

Reflect

两者比较

相通点

不同点


Proxy

Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。

可以看到,mdn对proxy的解释是创建一个对象的代理,不难想到,vue3的响应式数据并不会污染源数据。

它用于修改某些操作的默认行为,即对编程语言层面进行修改,属于“元编程”,Proxy意思为“代理”,即在访问对象之前建立一道“拦截”,任何访问该对象的操作之前都会通过这道“拦截”,即执行Proxy里面定义的方法。

语法

const p = new Proxy(target, handler)

参数解释:

target

要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。

handler

一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p 的行为。

Proxy一共支持13种拦截操作(不是Proxy自身的函数,是handler对象支持的方法):

  • apply(target, object, args)
  • construct(target, args)
  • get(target, propKey, receiver)
  • set(target, propKey, value, receiver)
  • defineProperty(target, propKey, propDesc)
  • deleteProperty(target, propKey)
  • has(target, propKey)
  • ownKeys(target)
  • isExtensible(target)
  • preventExtensions(target)
  • getOwnPropertyDescriptor(target, propKey)
  • getPrototypeOf(target)
  • setPrototypeOf(target, proto)

具体可看proxy传送门

案例:实现观察者模

const observers = new Set();

const observed = fn => observers.add(fn);
const observable = obj => new Proxy(obj, {
    set: function(target, key, value, receiver) {
          const result = Reflect.set(target, key, value, receiver);
          observers.forEach(observer => observer());
          return result;
    }
});

Reflect

Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法。这些方法与上面proxy handlers的13个方法相同Reflect不是一个函数对象,因此它是不可构造的

与大多数全局对象不同,Reflect并非一个构造函数,所以不能通过new运算符对其进行调用,或者将Reflect对象作为一个函数来调用。Reflect的所有属性和方法都是静态的(就像Math对象)。

案例:检测一个对象是否存在特定属性

const duck = {
  name: 'Maurice',
  color: 'white',
  greeting: function() {
    console.log(`Quaaaack! My name is ${this.name}`);
  }
}

Reflect.has(duck, 'color');
// true
Reflect.has(duck, 'haircut');
// false

具体可看Reflect传送门

两者比较

相通点

  • Proxy和Reflect都是es6为了操作对象而提供的新API
  • Proxy和Reflect经常混用,例如上面实现观察者模式
  • Reflect对象的方法与Proxy对象的方法一一对应,只要是Proxy对象的方法,就能在Reflect对象上找到对应的方法。这就让Proxy对象可以方便地调用对应的Reflect方法,完成默认行为,作为修改行为的基础。也就是说,不管Proxy怎么修改默认行为,你总可以在Reflect上获取默认行为。

不同点

  • Proxy是拦截对象的操作并定义拦截时具体执行什么操作;而Reflect其实是执行了对象的操作
  • 按我理解,Proxy是改写了对象原有方法;而Reflect像是要抽离原来Object上的方法,它就是是调用Object原有方法的函数,目的是将数据和逻辑代码分离。这样以后可能Obejct就只是数据,想要对其操作要用Reflect。

proxy的用处:

  1. 实现拦截和监视外部对对象的访问。
  2. 降低函数和类的复杂度,优雅的写出代理代码。
  3. 在复杂操作前对操作进行校验或对所需资源进行管理。

proxy的应用场景:

  1. 抽离校验模块。
  2. 私有属性。
  3. 访问日志。
  4. 预警和拦截。
  5. 过滤操作。
  6. 中断代理。

reflect的好处:

  1. 可以把一些不仅仅是Object含有的工具函数,统一起来,比如Reflect.apply,这是针对Function,而不是针对Object的,这些函数放到Object上显然不合适,放在Reflect上,第一没有什么歧义,第二增加了使用的便利性;
  2. 修改某些Object方法的返回结果,让其变得更合理。比如,Object.defineProperty(obj, name, desc)在无法定义属性时,会抛出一个错误,而Reflect.defineProperty(obj, name, desc)则会返回false。

  3. 让Object操作都变成函数行为。某些Object操作是命令式,例如把delete等命令式操作,改为Reflect.delete的函数式操作,可以减少保留字的个数;

    比如name in obj和delete obj[name],

    而Reflect.has(obj, name)和Reflect.deleteProperty(obj, name)让它们变成了函数行为

  4. 把散落的工具函数集中到一个统一的对象上,可以保持其他对象的简洁性

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端阿彬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值