前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >[初探] proxy 的优势与使用场景

[初探] proxy 的优势与使用场景

作者头像
守候i
发布于 2020-08-20 08:31:40
发布于 2020-08-20 08:31:40
1.1K00
代码可运行
举报
文章被收录于专栏:守候书阁守候书阁
运行总次数:0
代码可运行

1.前言

随着 vue3.x 的消息越来越多,proxy 的讨论也。相对于 Object.definePropertyproxy 有什么区别,有什么优势,以及可以应用在什么地方。该文章就简单的介绍下

2.Object.defineProperty

proxy 之前,先回顾下 Object.defineProperty 。大家都知道,vue2.x 以及之前的版本是使用 Object.defineProperty 实现数据的双向绑定的,至于是怎样绑定的呢?下面简单实现一下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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 上的描述是:对象用于定义基本操作的自定义行为(如属性查找、赋值、枚举、函数调用等)

简单来说就是,可以在对目标对象设置一层拦截。无论对目标对象进行什么操作,都要经过这层拦截

听上去似乎,proxyObject.defineProperty 要好用,并且简单很多,实际上就是如此。下面用 proxy 对上面的代码进行改写试下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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 实现。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let ecArrayProxy = {
  get (target, key, receiver) {
    let _index=key<0?target.length+Number(key):key
    return Reflect.get(target, _index, receiver)
  }
}
let arr=new Proxy([1,2,3],ecArrayProxy)

4-2.表单校验

在对表单的值进行改动的时候,可以在 set 里面进行拦截,判断值是否合法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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位代表性别,男单女双。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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?'男':'女', receiver)
    }
    return Reflect.set(target, key, value, receiver)
  }
}
let obj=new Proxy({cardNumber:''},ecCardNumber)

4-4.数据格式化

比如有一个需求,需要传时间戳给到后端,但是前端拿到的是一个时间字符串,这个也可以用 proxy 进行拦截,当得到时间字符串之后,可以自动加上时间戳。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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优劣如何?

简单通俗的理解Vue3.0中的Proxy

小结

proxyObject.defineproperty 的一些区别,以及 proxy 的优势,使用场景,暂时就介绍到这里了。这篇文章介绍的不算深入,理解起来不难。对于 proxy ,笔者也打算继续深入学习,如果往后有收获,也会第一时间分享。如果文章有什么错误,或者有什么建议,欢迎评论区留言。

-------------------------华丽的分割线--------------------

想了解更多,和我交流,请添加我微信。或者关注我的微信公众号:守候书阁

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-06-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 守候书阁 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Vue3 为何使用 Proxy 实现数据监听
vue3 响应式数据放弃了 Object.defineProperty,而使用==Proxy==来代替它
Krry
2020/08/03
1K0
面试官:Vue3.0里为什么要用 Proxy API 替代 defineProperty API ?
定义:Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象
@超人
2021/02/26
6480
面试官:Vue3.0里为什么要用 Proxy API 替代 defineProperty API ?
简单通俗的理解Vue3.0中的Proxy
什么是代理呢,可以理解为在对象之前设置一个“拦截”,当该对象被访问的时候,都必须经过这层拦截。意味着你可以在这层拦截中进行各种操作。比如你可以在这层拦截中对原对象进行处理,返回你想返回的数据结构。
木子星兮
2020/03/12
1.5K0
简单通俗的理解Vue3.0中的Proxy
你不知道的 Proxy:用 ES6 Proxy 能做哪些有意思的事情?
在武侠小说中,经常看到这样的桥段。某位武林人士前来拜访德高望重的帮派掌门,往往需要经过手下弟子的通报。如果掌门外出或者不想见来人,就会让弟子婉拒。
尹光耀
2021/10/19
1.2K0
Vue篇(004)-Vue3 为什么要用 Proxy 代替 Object.defineProperty
1. 在 Vue 中,Object.defineProperty 无法监控到数组下标的变化,导致直接通过数组的下标给数组设置值,不能实时响应。
齐丶先丶森
2022/05/12
8060
Vue3 的响应式和以前有什么区别,Proxy 无敌?(面试热门,源码级详解)
大家都知道,Vue2 里的响应式其实有点像是一个半完全体,对于对象上新增的属性无能为力,对于数组则需要拦截它的原型方法来实现响应式。
ssh_晨曦时梦见兮
2020/04/14
7760
每日一题之Vue数据劫持原理是什么?
定义: 数据劫持,指的是在访问或者修改对象的某个属性时,通过一段代码拦截这个行为,进行额外的操作或者修改返回结果。
bb_xiaxia1998
2022/10/06
5150
每天3分钟,重学ES6-ES12(十九)Proxy-Reflect
持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第32天,点击查看活动详情
虎妞先生
2022/09/19
2470
ES6-标准入门·Proxy 和 Reflect
ES6 新增 Proxy 和 Reflect,两者相辅相成,功能颇为强大,但工作中基本未被提及,这里略微学习一下,不求甚解,待到 coding 时遇到再温故知新。
数媒派
2022/12/01
4310
JS 中的 Reflect 和 Proxy
Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法。Reflect不是一个函数对象,因此它是不可构造的。Reflect的所有的方法都是静态的就和Math一样,目前它还没有静态属性。
羽月
2022/10/08
9110
重学ES6之代理Proxy和反射Reflect
Proxy代理,Reflect反射。 调用new Proxy()可以创建代替其他目标(target)对象的代理,它虚拟化了目标,所以两者看起来功能一致。 代理可以拦截JavaScript引擎内部目标的底层对象操作,这些底层操作被拦截后会触发相应特定操作的陷阱函数。(钩子函数Hook) 反射API以Refelect对象的形式出现,对象中方法的默认特性与相同的底层操作一致,而代理可以覆写这些操作,每个代理陷阱对应一个命名和参数都相同的Refelect方法。 Tips 无论是Object.definP
19组清风
2021/11/15
4800
Vue中数组变动监听
Vue的通过数据劫持的方式实现数据的双向绑定,即使用Object.defineProperty()来实现对属性的劫持,但是Object.defineProperty()中的setter是无法直接实现数组中值的改变的劫持行为的,想要实现对于数组下标直接访问的劫持需要使用索引对每一个值进行劫持,但是在Vue中考虑性能问题并未采用这种方式,所以需要特殊处理数组的变动。
WindRunnerMax
2020/09/16
5980
Vue3.0 框架为什么要使用 Proxy ?
前几天面试的时候,面试官问到了这个问题,感觉自己答的不是特别好,在这里整理一下~ 文章篇幅会比较长,但是看完一定会收获满满~希望你坚持看下去呀~
前端达人
2022/04/18
7180
Vue3.0 之 Proxy
如果你平时有关注 Vue 的进展的话,可能已经知道了在 Vue3.0 中将会通过 Proxy 来替换原本的 Object.defineProperty 来实现数据响应式。 Proxy 是 ES6 中新增的功能,它可以用来自定义对象中的操作。
EchoROne
2022/08/15
3950
学习Vue3.0,先来了解一下Proxy
据悉Vue3.0的正式版将要在本月(8月)发布,从发布到正式投入到正式项目中,还需要一定的过渡期,但我们不能一直等到Vue3正式投入到项目中的时候才去学习,提前学习,让你更快一步掌握Vue3.0,升职加薪迎娶白富美就靠它了。不过在学习Vue3之前,还需要先了解一下Proxy,它是Vue3.0实现数据双向绑定的基础。
前端进击者
2021/07/27
6760
从 Proxy 到 Vue3 响应式
最近想再回顾下 Proxy 这一部分的内容, 顺便也看看他的应用场景, 刚好在 Vue3 的响应式 API 中有使用, 所以就结合着一起复习下, 顺便总结记录一番. 如果只对 Vue3 的响应式感兴趣的, 可以直接跳到文章的第二部分.
BLUSE
2022/12/02
1.2K1
Proxy代理数据拦截方法
Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。
微芒不朽
2022/11/30
3840
Proxy代理数据拦截方法
Reflect
Reflect对象与Proxy对象一样,也是 ES6 为了操作对象而提供的新 API。Reflect对象的设计目的有这样几个。
小小杰啊
2022/12/21
4580
Js中Proxy对象
Proxy对象用于定义基本操作的自定义行为,例如属性查找、赋值、枚举、函数调用等。
WindRunnerMax
2020/11/24
2.6K0
Vue3 的响应式和以前有什么区别,Proxy 无敌?
大家都知道,Vue2 里的响应式其实有点像是一个半完全体,对于对象上新增的属性无能为力,对于数组则需要拦截它的原型方法来实现响应式。
ssh_晨曦时梦见兮
2020/10/15
1.3K0
相关推荐
Vue3 为何使用 Proxy 实现数据监听
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文