1.前言
随着 vue3.x
的消息越来越多, proxy
的讨论也。相对于 Object.defineProperty
, proxy
有什么区别,有什么优势,以及可以应用在什么地方。该文章就简单的介绍下
2.Object.defineProperty
讲 proxy
之前,先回顾下 Object.defineProperty
。大家都知道, vue2.x
以及之前的版本是使用 Object.defineProperty
实现数据的双向绑定的,至于是怎样绑定的呢?下面简单实现一下
function observer(obj) { if (typeof obj ==='object') { for (let key in obj) { defineReactive(obj, key, obj[key]) } } } function defineReactive(obj, key, value) { //针对value是对象,递归检测 observer(value) //劫持对象的key Object.defineProperty(obj, key, { get() { console.log('获取:'+key) return value }, set(val) { //针对所设置的val是对象 observer(val) console.log(key+"-数据改变了") value = val } }) } let obj={ name:'守候', flag:{ book:{ name:'js', page:325 }, interest:['火锅','旅游'], } } observer(obj)
在浏览器的 console
执行一下,似乎能正常运行
但是实际上, Object.defineProperty
问题有以下几个
问题1.删除或者增加对象属性无法监听到
比如增加一个属性 gender
,由于在执行 observer(obj)
的时候,没有这个属性,所以这个无法监听到。删除的属性也是无法监听到
增加属性的时候, vue
需要使用 $set
进行操作, $set
的内部也是使用 Object.defineProperty
进行操作
问题2.数组的变化无法监听到
由上图得知,虽然数组属性实际上是修改成功了,但是不能被监听到
问题3. 由于是使用递归遍历对象,使用 Object.defineProperty
劫持对象的属性,如果遍历的对象层级比较深,花的时间比较久,甚至有性能的问题
3.proxy
对于 proxy
,在 mdn 上的描述是: 对象用于定义基本操作的自定义行为(如属性查找、赋值、枚举、函数调用等)
简单来说就是,可以在对目标对象设置一层拦截。无论对目标对象进行什么操作,都要经过这层拦截
听上去似乎, proxy
比 Object.defineProperty
要好用,并且简单很多,实际上就是如此。下面用 proxy 对上面的代码进行改写试下
function observerProxy(obj){ let handler = { get (target, key, receiver) { console.log('获取:'+key) // 如果是对象,就递归添加 proxy 拦截 if (typeof target[key] === 'object' && target[key] !== null) { return new Proxy(target[key], handler) } return Reflect.get(target, key, receiver) }, set (target, key, value, receiver) { console.log(key+"-数据改变了") return Reflect.set(target, key, value, receiver) } } return new Proxy(obj, handler) } let obj={ name:'守候', flag:{ book:{ name:'js', page:325 }, interest:['火锅','旅游'], } } let objTest=observerProxy(obj)
也是一样的效果
而且,能做到 Object.defineProperty
做不到的事情,比如增加一个属性 gender
,能够监听到
操作数组,也能监听到
最后敲一下黑板,简单总结一下两者的区别
1. Object.defineProperty
拦截的是对象的属性,会改变原对象。 proxy
是拦截整个对象,通过 new 生成一个新对象,不会改变原对象。
2. proxy
的拦截方式,除了上面的 get 和 set ,还有 11 种。选择的方式很多 Proxy ,也可以监听一些 Object.defineProperty
监听不到的操作,比如监听数组,监听对象属性的新增,删除等。
4.proxy 使用场景
关于 proxy
的使用场景,受限于篇幅,这里就简单列举几个,更多的可以移步我的 github 笔记或者 mdn 。
看到这里,两者的区别,和 proxy
的优势已经知道个大概了。但是在开发上,有哪些场景可以使用到 proxy
呢,下面列举个可能会遇上的情况
4-1.负索引数组
在使用 splice(-1)
, slice(-1)
等 API 的时候,当输入负数的时候,会定位到数组的最后一项,但是在普通数组上,并不能使用负数。 [1,2,3][-1]
这个代码并不能输出 3 。要让上面的代码输出 3 , 也可以使用 proxy
实现。
let ecArrayProxy = { get (target, key, receiver) { let _index=key<0"text-align: center">4-2.表单校验
在对表单的值进行改动的时候,可以在
set
里面进行拦截,判断值是否合法let ecValidate = { set (target, key, value, receiver) { if (key === 'age') { //如果值小于0,或者不是正整数 if (value<0||!Number.isInteger(value)) { throw new TypeError('请输入正确的年龄'); } } return Reflect.set(target, key, value, receiver) } } let obj=new Proxy({age:18},ecValidate) obj.age=16 obj.age='少年'4-3.增加附加属性
比如有一个需求,保证用户输入正确身份证号码之后,把出生年月,籍贯,性别都添加进用户信息里面
众所周知,身份证号码第一和第二位代表所在省(自治区,直辖市,特别行政区),第三和第四位代表所在市(地级市、自治州、盟及国家直辖市所属市辖区和县的汇总码)。第七至第十四位是出生年月日。低17位代表性别,男单女双。
const PROVINCE_NUMBER={ 44:'广东省', 46:'海南省' } const CITY_NUMBER={ 4401:'广州市', 4601:'海口市' } let ecCardNumber = { set (target, key, value, receiver) { if(key === 'cardNumber'){ Reflect.set(target, 'hometown', PROVINCE_NUMBER[value.substr(0,2)]+CITY_NUMBER[value.substr(0,4)], receiver) Reflect.set(target, 'date', value.substr(6,8), receiver) Reflect.set(target, 'gender', value.substr(-2,1)%2===1"text-align: center">4-4.数据格式化
比如有一个需求,需要传时间戳给到后端,但是前端拿到的是一个时间字符串,这个也可以用
proxy
进行拦截,当得到时间字符串之后,可以自动加上时间戳。let ecDate = { set (target, key, value, receiver) { if(key === 'date'){ Reflect.set(target, 'timeStamp', +new Date(value), receiver) } return Reflect.set(target, key, value, receiver) } } let obj=new Proxy({date:''},ecDate)参考链接
Proxy
面试官: 实现双向绑定Proxy比defineproperty优劣如何"_blank" href="https://juejin.im/post/5ac61da66fb9a028c71eae1b" rel="external nofollow" >简单通俗的理解Vue3.0中的Proxy
小结
proxy
和Object.defineproperty
的一些区别,以及proxy
的优势,使用场景,暂时就介绍到这里了。这篇文章介绍的不算深入,理解圈起来不难。对于 proxy ,笔者也打算继续深入学习,如果往后有收获,也会第一时间分享。如果文章有什么错误,或者有什么建议,欢迎评论区留言。
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。
更新日志
- 凤飞飞《我们的主题曲》飞跃制作[正版原抓WAV+CUE]
- 刘嘉亮《亮情歌2》[WAV+CUE][1G]
- 红馆40·谭咏麟《歌者恋歌浓情30年演唱会》3CD[低速原抓WAV+CUE][1.8G]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[320K/MP3][193.25MB]
- 【轻音乐】曼托凡尼乐团《精选辑》2CD.1998[FLAC+CUE整轨]
- 邝美云《心中有爱》1989年香港DMIJP版1MTO东芝首版[WAV+CUE]
- 群星《情叹-发烧女声DSD》天籁女声发烧碟[WAV+CUE]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[FLAC/分轨][748.03MB]
- 理想混蛋《Origin Sessions》[320K/MP3][37.47MB]
- 公馆青少年《我其实一点都不酷》[320K/MP3][78.78MB]
- 群星《情叹-发烧男声DSD》最值得珍藏的完美男声[WAV+CUE]
- 群星《国韵飘香·贵妃醉酒HQCD黑胶王》2CD[WAV]
- 卫兰《DAUGHTER》【低速原抓WAV+CUE】
- 公馆青少年《我其实一点都不酷》[FLAC/分轨][398.22MB]
- ZWEI《迟暮的花 (Explicit)》[320K/MP3][57.16MB]