首页 > 其他分享 >为什么vue3要选用proxy,好处是什么?

为什么vue3要选用proxy,好处是什么?

时间:2022-10-21 17:01:03浏览次数:93  
标签:对象 Object Reflect 选用 Proxy vue3 属性 proxy

提问

  1. Object.defineProperty()和proxy的区别?
  2. 为什么vue3要选用proxy,好处是什么?

proxy

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

Proxy的用法,这个大家都知道

const p = new Proxy(target, handler)

剖析一下内部实现 ECMAScript 2017 (ECMA-262)
在这里插入图片描述

可以看到接收两个参数(target,handler)

  1. 如果target是undefined,报错
  2. 运行ProxyCreate(target, handler)

下面是ProxyCreate的实现

在这里插入图片描述

排除一下错误处理,核心代码从5开始
先创建一个新的空对象p,

设置p对象的内部方法(除了[call]]和[[Construct]])设置为[9.5指定的定义,

然后设置p的call和Construct方法,

再设置内部属性[[ProxyTarget]]和[[ProxyHandler]]

返回对象p

我们可以用它们拦截什么?

对于对象的大多数操作,JavaScript 规范中有一个所谓的“内部方法”,它描述了最底层的工作方式。例如 [[Get]],用于读取属性的内部方法,[[Set]],用于写入属性的内部方法,等等。这些方法仅在规范中使用,我们不能直接通过方法名调用它们。

Proxy 捕捉器会拦截这些方法的调用。它们在 proxy 规范 和下表中被列出。

对于每个内部方法,此表中都有一个捕捉器:可用于添加到 new Proxyhandler 参数中以拦截操作的方法名称:

对于对象的大多数操作,JavaScript 规范中有一个所谓的“内部方法”,它描述了最底层的工作方式。例如 [[Get]],用于读取属性的内部方法,[[Set]],用于写入属性的内部方法,等等。这些方法仅在规范中使用,我们不能直接通过方法名调用它们。

Proxy 捕捉器会拦截这些方法的调用。它们在 proxy 规范 和下表中被列出。

对于每个内部方法,此表中都有一个捕捉器:可用于添加到 new Proxyhandler 参数中以拦截操作的方法名称:

内部方法 Handler 方法 何时触发
[[Get]] get 读取属性
[[Set]] set 写入属性
[[HasProperty]] has in 操作符
[[Delete]] deleteProperty delete 操作符
[[Call]] apply 函数调用
[[Construct]] construct new 操作符
[GetPrototypeOf]] getPrototypeOf [Object.getPrototypeOf
[SetPrototypeOf]] setPrototypeOf [Object.setPrototypeOf
[IsExtensible]] isExtensible [Object.isExtensible
[PreventExtensions]] preventExtensions [Object.preventExtensions
[DefineOwnProperty]] defineProperty [Object.defineProperty, Object.defineProperties
[GetOwnProperty]] getOwnPropertyDescriptor [Object.getOwnPropertyDescriptor, for..in, Object.keys/values/entries
[OwnPropertyKeys]] ownKeys [Object.getOwnPropertyNames, Object.getOwnPropertySymbols, for..in, Object.keys/values/entries

Reflect

Reflect 是一个内建对象,可简化 Proxy 的创建。

前面所讲过的内部方法,例如 [[Get]][[Set]] 等,都只是规范性的,不能直接调用。

Reflect 对象使调用这些内部方法成为了可能。它的方法是内部方法的最小包装。

尤其是,Reflect 允许我们将操作符(newdelete,……)作为函数(Reflect.constructReflect.deleteProperty,……)执行调用。这是一个有趣的功能,但是这里还有一点很重要。

对于每个可被 Proxy 捕获的内部方法,在 Reflect 中都有一个对应的方法,其名称和参数与 Proxy 捕捉器相同。

所以,我们可以使用 Reflect 来将操作转发给原始对象。

我们可以把捕捉器重写得更短:

get(target, prop, receiver) {
  return Reflect.get( ... arguments);
}

Reflect 调用的命名与捕捉器的命名完全相同,并且接受相同的参数。它们是以这种方式专门设计的。

因此,return Reflect... 提供了一个安全的方式,可以轻松地转发操作,并确保我们不会忘记与此相关的任何内容。

proxy 的局限性

1. 无法代理内部插槽

许多内建对象,例如 MapSetDatePromise 等,都使用了所谓的“内部插槽”。

例如:

let map = new Map();

let proxy = new Proxy(map, {});

proxy.set('test', 1); // Error

解决方法 在get的时候将get要返回的值先绑定目标对象后返回

let map = new Map();

let proxy = new Proxy(map, {
  get(target, prop, receiver) {
    let value = Reflect.get(...arguments);
return typeof value == 'function' ? value.bind(target) : value;
  }
});

proxy.set('test', 1);
alert(proxy.get('test')); // 1(工作了!)

2. 私有字段也和上面一样

3. peoxy != target

这个很好理解 ,代理对象和目标对象是不=== 的

总结

Proxy 是对象的包装器,将代理上的操作转发到对象,并可以选择捕获其中一些操作。

它可以包装任何类型的对象,包括类和函数。

语法为:

let proxy = new Proxy(target, {
  /* trap */
});

……然后,我们应该在所有地方使用 proxy 而不是 target。代理没有自己的属性或方法。如果提供了捕捉器(trap),它将捕获操作,否则会将其转发给 target 对象。

我们可以捕获

  • get,set,deleteProperty 等操作
  • 函数调用(apply捕捉器)
  • new操作(construct 捕捉器)

Reflect 旨在补充 Proxy。对于任意 Proxy 捕捉器,都有一个带有相同参数的 Reflect 调用。我们应该使用它们将调用转发给目标对象。

Proxy的局限

  1. 无法代理内部对象的内部插槽
  2. 无法代理私有字段
  3. 代理对象和目标对象不相等

Object.defineProperty

Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

语法

Object.defineProperties(obj, props)

描述

对象里目前存在的属性描述符有两种主要形式:数据(属性)描述符存取描述符(访问器属性)数据描述符是一个具有值的属性,该值可以是可写的,也可以是不可写的。存取描述符是由 getter 函数和 setter 函数所描述的属性。一个描述符只能是这两者其中之一;不能同时是两者。参考视频讲解:进入学习

属性描述符

  • value — 值
  • writable — 如果为 true,则值可以被修改,否则它是只可读的。
  • enumerable — 如果为 true,则会被在循环中列出,否则不会被列出。
  • configurable — 如果为 true,则此属性可以被删除,这些特性也可以被修改,否则不可以。

访问器属性

  • get —— 一个没有参数的函数,在读取属性时工作,
  • set —— 带有一个参数的函数,当属性被设置时调用,
  • enumerable —— 与数据属性的相同,
  • configurable —— 与数据属性的相同。

回答第一个问题

Object.defineProperty()和proxy的区别?

Object.defineProperty Proxy
新增/修改一个对象的属性,定义其描述,返回该对象 代理目标对象,对其操作拦截,返回代理对象
有数据描述符和访问器描述符两种 对其13种操作进行拦截
只能代理常规对象 可以代理任何对象(函数,数组,类)
- 不能代理内部对象的内部插槽

回答第二个问题

为什么vue3要选用proxy,好处是什么?

  • 能够代理任何对象包括数组和函数,对象
  • 比Object.defineProperty()更多的基本语义得操作(get,set,delete...)
  • 不用循环遍历对象然后再使用Object.defineProperty(),Proxy可以代理对象内所有的属性。
  • Object.defineProperty()只能劫持对象的属性(给对象添加属性vue无法检测到)

标签:对象,Object,Reflect,选用,Proxy,vue3,属性,proxy
From: https://www.cnblogs.com/hellocoder2029/p/16814031.html

相关文章

  • 使用MySQL Proxy实现读写分离的正确操作
    环境:CentOS7本文适用于包括Docker的所有环境,Docker安装这里不在阐述。第一步从官网下载tar包。官网链接:https://downloads.mysql.com/archives/proxy/a)直接在CentOS上......
  • Vue3 SFC 和 TSX 方式自定义组件实现 v-model
    1v-model1.1理解v-modelv-model是vue3中的一个内置指令,很多表单元素都可以使用这个属性,如input、checkbox等,咱可以在自定义组件中实现v-model。v-model本质上......
  • 【http代理】ProxyPool代码样例
    1.此样例是私密代理简单IP池管理的实现2.requests不是python原生库,需要安装才能使用:pipinstallrequests3.支持Python2.7和Python3#!/usr/bin/envpython#-*-encodi......
  • Vue3快速上手
    Vue3快速上手1.Vue3简介2020年9月18日,Vue.js发布3.0版本,代号:OnePiece(海贼王)耗时2年多、2600+次提交、30+个RFC、600+次PR、99位贡献者github上的tags地址:https://gi......
  • 基于tauri+vue3.x多开窗口|Tauri创建多窗体实践
    最近一种在捣鼓Tauri集成Vue3技术开发桌面端应用实践,tauri实现创建多窗口,窗口之间通讯功能。开始正文之前,先来了解下tauri结合vue3.js快速创建项目。tauri在......
  • vue3使用echarts插件并实现点击下载图表功能
    接到一个新的需求,就是用vue3制作一幅世界地图,并实现点击下载按钮将图表转变为图片下载到本地。使用插件: html2canvasnpm安装: npminstallhtml2canvas组件引入: import......
  • Vue3响应式助你轻松实现国际化
    本文为Varlet组件库源码主题阅读系列第十篇,也是最后一篇,读完本篇,可以了解到如何通过创建一个Vue3响应式对象就可以轻松实现国际化的需求。Varlet组件库支持多语言切换,使......
  • Vue3响应式助你轻松实现国际化
    本文为Varlet组件库源码主题阅读系列第十篇,也是最后一篇,读完本篇,可以了解到如何通过创建一个Vue3响应式对象就可以轻松实现国际化的需求。Varlet组件库支持多语言切换,使......
  • Vue3.x+element-plus+ts踩坑笔记
    闲聊前段时间小颖在B站找了个学习vue3+TS的视频,自己尝试着搭建了一些基础代码,在实现功能的过程中遇到了一些问题,为了防止自己遗忘,写个随笔记录一下嘻嘻项目代码git地址:......
  • vue3:vue+nginx+php进行服务端部署的配置(nginx/1.18.0 / [email protected])
    一,开发环境中的配置:1,前端:vue的vue.config.jsconst{defineConfig}=require('@vue/cli-service')module.exports=defineConfig({transpileDependencies:t......