vue proxy 的优势与使用场景实现


Posted in Javascript onJune 15, 2020

1.前言

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

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 执行一下,似乎能正常运行

vue proxy 的优势与使用场景实现

但是实际上, Object.defineProperty 问题有以下几个

问题1.删除或者增加对象属性无法监听到

比如增加一个属性 gender ,由于在执行 observer(obj) 的时候,没有这个属性,所以这个无法监听到。删除的属性也是无法监听到

增加属性的时候, vue 需要使用 $set 进行操作, $set 的内部也是使用 Object.defineProperty 进行操作

vue proxy 的优势与使用场景实现

问题2.数组的变化无法监听到

vue proxy 的优势与使用场景实现

由上图得知,虽然数组属性实际上是修改成功了,但是不能被监听到

问题3. 由于是使用递归遍历对象,使用 Object.defineProperty 劫持对象的属性,如果遍历的对象层级比较深,花的时间比较久,甚至有性能的问题

3.proxy

对于 proxy ,在 mdn 上的描述是: 对象用于定义基本操作的自定义行为(如属性查找、赋值、枚举、函数调用等)

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

听上去似乎, proxyObject.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)

也是一样的效果

vue proxy 的优势与使用场景实现

而且,能做到 Object.defineProperty 做不到的事情,比如增加一个属性 gender ,能够监听到

vue proxy 的优势与使用场景实现

操作数组,也能监听到

vue proxy 的优势与使用场景实现

最后敲一下黑板,简单总结一下两者的区别

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?target.length+Number(key):key
  return Reflect.get(target, _index, receiver)
 }
}
let arr=new Proxy([1,2,3],ecArrayProxy)

vue proxy 的优势与使用场景实现 

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='少年'

vue proxy 的优势与使用场景实现 

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?'男':'女', receiver)
  }
  return Reflect.set(target, key, value, receiver)
 }
}
let obj=new Proxy({cardNumber:''},ecCardNumber)

vue proxy 的优势与使用场景实现 

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)

vue proxy 的优势与使用场景实现 

参考链接

Proxy

面试官: 实现双向绑定Proxy比defineproperty优劣如何?

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

小结

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

到此这篇关于vue proxy 的优势与使用场景实现的文章就介绍到这了,更多相关vue proxy 使用场景内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
js 编写规范
Mar 03 Javascript
js弹出窗口之弹出层的小例子
Jun 17 Javascript
js判断设备是否为PC并调整图片大小
Feb 12 Javascript
可编辑下拉框的2种实现方式
Jun 13 Javascript
PHP+jQuery+Ajax+Mysql如何实现发表心情功能
Aug 06 Javascript
再JavaScript的jQuery库中编写动画效果的指南
Aug 13 Javascript
基于vue实现分页/翻页组件paginator示例
Mar 09 Javascript
jQuery实现文章图片弹出放大效果
Apr 06 jQuery
微信小程序实现页面浮动导航
Jan 08 Javascript
微信小程序后端无法保持session的原因及解决办法问题
Mar 20 Javascript
微信小程序 获取手机号 JavaScript解密示例代码详解
May 14 Javascript
浅谈在vue-cli3项目中解决动态引入图片img404的问题
Aug 04 Javascript
原生JS利用transform实现banner的无限滚动示例代码
Jun 15 #Javascript
koa中间件核心(koa-compose)源码解读分析
Jun 15 #Javascript
为react组件库添加typescript类型提示的方法
Jun 15 #Javascript
JavaScript中的全局属性与方法深入解析
Jun 14 #Javascript
Vue使用Three.js加载glTF模型的方法详解
Jun 14 #Javascript
浅谈Vue 自动化部署打包上线
Jun 14 #Javascript
JS定时器如何实现提交成功提示功能
Jun 12 #Javascript
You might like
php实现的MySQL通用查询程序
2007/03/11 PHP
thinkphp3.2.3 分页代码分享
2016/07/28 PHP
PHP实现Session入库/存入redis的方法
2017/05/04 PHP
yii2.0整合阿里云oss删除单个文件的方法
2017/09/19 PHP
php使用yield对性能提升的测试实例分析
2019/09/19 PHP
asp.net+js 实现无刷新上传解析csv文件的代码
2010/05/17 Javascript
JS实现控制表格行内容垂直对齐的方法
2015/03/30 Javascript
JavaScript中实现map功能代码分享
2015/06/11 Javascript
JS事件添加和移出的兼容写法示例
2016/06/20 Javascript
9个让JavaScript调试更简单的Console命令
2016/11/14 Javascript
AngularJS表单提交实例详解
2017/02/18 Javascript
vue系列之动态路由详解【原创】
2017/09/10 Javascript
微信小程序倒计时功能实例代码
2018/07/17 Javascript
如何在postman中添加cookie信息步骤解析
2020/06/30 Javascript
[01:38]DOTA2第二届亚洲邀请赛中国区预选赛出线战队晋级之路
2017/01/17 DOTA
Python学习入门之区块链详解
2017/07/25 Python
Python实现图片转字符画的示例
2017/08/22 Python
scrapy爬虫完整实例
2018/01/25 Python
Window10+Python3.5安装opencv的教程推荐
2018/04/02 Python
Python3中关于cookie的创建与保存
2018/10/21 Python
Python中GeoJson和bokeh-1的使用讲解
2019/01/03 Python
python GUI库图形界面开发之PyQt5结合Qt Designer创建信号与槽的详细方法与实例
2020/03/08 Python
Python大批量搜索引擎图像爬虫工具详解
2020/11/16 Python
法国最大电子商务平台:Cdiscount
2018/03/13 全球购物
如果NULL定义成#define NULL((char *)0)难道不就可以向函数传入不加转换的NULL了吗
2012/02/15 面试题
管理心得体会
2013/12/28 职场文书
园林资料员岗位职责
2013/12/30 职场文书
文明教师事迹材料
2014/01/16 职场文书
置业顾问岗位职责
2014/03/02 职场文书
师范类求职信
2014/06/21 职场文书
住宿生擅自离校检讨书
2014/09/22 职场文书
房屋租赁协议书
2014/10/18 职场文书
工作期间打牌检讨书范文
2014/11/20 职场文书
辩论会主持词
2015/07/03 职场文书
大学生先进个人主要事迹材料
2015/11/04 职场文书
java中用float时,数字后面加f,这样是为什么你知道吗
2021/09/04 Java/Android