当前位置: 首页 > Web前端 > vue.js

Vue3.0使用ES6Proxy代替Object.defineProperty

时间:2023-03-31 17:24:02 vue.js

阅读本文,你将了解什么是JavaScript中的Proxy?我能做些什么?Vue3.0开始使用Proxy而不是Object.definePropertyProxy来解释它是什么。参考MDN,链接直达名词解释Proxy对象用于定义基本操作(如属性查找、赋值、枚举、函数调用等)的自定义行为Proxy用于修改某些操作的默认行为,也可以是理解为在目标对象之前设置一层拦截。所有外部访问都要先经过这一层拦截,所以提供了一种机制来过滤外部访问,修改语法constp=newProxy(target,handler)target:Proxy要包裹的目标对象(可以是任意类型ofobject,includingnativearrays,functions,andevenanotherproxy)handler:处理对代理对象的各种操作(在空对象的情况下,基本可以理解为第一个参数的浅拷贝)简而言之:target是您要代理的对象;而handler是一个函数对象,定义了所有你想要管理的操作对象而不是target,包括:*handler.has(target,prop):in操作符的捕手,拦截HasProperty操作prop):属性读取操作的捕手*handler.set(target,prop,value):属性设置操作的捕手*handler.apply(target,object,args):函数调用操作的捕手,拦截函数调用,调用并应用操作handler.getPrototypeOf():Object.getPrototypeOfmethodcatcherhandler.setPrototypeOf():Object.setPrototypeOfmethodcatcherhandler.isExtensible():Object.isExtensiblemethodcatcherhandler.preventExtensions():Object.preventExtensionsmethodcatcherhandler.getOwnPropertyDescriptor():handler.defineProperty():Object.defineProperty方法的捕获器handler.deleteProperty():删除运算符的捕获器handler.ownKeys():Object.getOwnPropertyNames方法和Object.getOwnPropertySymbols方法的捕获器handler.construct():new运算符的捕获器注意:如果属性不可配置||不可写,该属性不能被代理,通过Proxy访问该属性会报错*标记的trap是本文涉及的Proxy它能做什么?代理模式在以下情况下通常很有用:拦截或控制对对象的访问通过在未经身份验证/准备好的情况下隐藏事务或辅助逻辑来降低方法/类的复杂性执行严重依赖于资源的操作1:javascript/拦截中的真正私有变量...in...操作/提供提示信息或阻止特定操作传统方法私有变量可以获取,可以修改代理设置私有变量私有变量,可以使用代理拦截对某个属性的请求,并进行限制或者直接返回undefined。您也可以使用has陷阱来掩盖此属性的存在。has方法拦截的是hasProperty操作,不是hasOwnProperty,所??以has...in方法不会判断一个属性是自己的属性还是继承的属性。注意:has...in可以被拦截,但是for...in不能被拦截,防止别人删除该属性。我们希望调用者知道该方法已被弃用。或者你想防止别人修改属性注意:如果Proxy代理起作用,一定是对Proxy实例进行操作,而不是对目标对象进行操作2:数据验证(见代码)使用Proxy代理进行简单的数据验证验证它太重了,直接在代理处理函数中添加逻辑。我们可以直接提取验证模块,只需要处理验证逻辑,不需要改变代理级别。3:使用代理记录对象访问那些高度依赖的资源,缓慢或频繁使用的方??法或接口,统计它们的使用或性能可以记录各种信息,而无需修改应用程序代码或阻塞代码执行。而你只需要在这些代码的基础上做一些小的修改,就可以记录下特征函数的执行性能。上面的例子是一个监听函数执行的代理,可以扩展为一个点函数。这里,Proxy陷阱为什么用get而不是apply呢?答案4:普通函数和构造函数之间的兼容性。如果构造函数调用没有用new关键字调用,Class对象会直接抛出异常。使用Proxy封装构造函数,使得构造函数也可以直接进行函数调用。5:深度值判断(见代码)需要解决的几个问题获取数据拦截xxx.xxx.xxx...无论哪里出现undefined都不能报错Proxy的get()传入的参数必须是对象简化不必要的代码,但是当target[prop]为undefined时,Proxyget()的入参变为undefined,但是Proxy的第一个入参必须是一个对象,obj为undefined时需要特殊处理,以便能够Deep值,所以使用一个空函数来设置拦截,使用applytrap来处理我们的理想应该是,如果属性是undefined,返回undefined,但是仍然支持访问更下层的属性而不是抛出错误遵循这个思路如果来了,很明显当属性是undefined的时候,也需要使用Proxy进行特殊处理,所以我们需要一个具有如下特点的get()方法getData(undefined)()===undefined;//truegetData(undefined).xxx.yyy.zzz();//这里的undefined不需要关注get(undefined).xxx是否是正确的值,因为必须要执行它才能获取值,所以只需要将undefined之后访问的所有属性都默认为undefined即可,所以我们需要在undefined被代理后返回一个对象。同时为了解决死循环执行的问题,当第一次检测到undefined时,停止执行。六:日志上报腾讯使用Proxy实现日志上报功能Vue3.0的Proxy&Object.definePropertyProxy劫持方式:代理整个对象,只需要做一层代理即可监听同层结构下的所有属性变化,包括增删属性本质:Proxy本质上是一种元编程的无损数据劫持。函数在原有对象的基础上派生出来,不影响原有对象,符合松耦合高内聚的设计理念Object.definePropertyhijacking方法:只能劫持对象的属性,不能直接代理对象流程:在get中收集依赖,设置数据时通知订阅者更新问题:Object.defineProperty虽然可以通过为属性设置getter/setter来完成数据的响应式,但是它并不是实现数据响应式的完美方案。在某些情况下,它需要打补丁或被黑客入侵。监听数组的变化1.Object.defineProperty无法监听新添加的属性。解决方案:提供一种方法,再次手动观察。如果需要监控,使用Vue.set()来重置添加属性的响应性。2.Object.defineProperty不能一次性监听对象的所有属性,比如对象属性的子属性解决方法:通过递归调用实现子属性的响应性3.Object.defineProperty不能响应数组操作解决方法:通过遍历重写数组原型方法操作方法,但仅限于push/pop/shift/unshift/splice/sort/reverse这七种方法中,无法检测到其他数组方法和数组的使用,无法监听数组索引和长度的变化.4.Proxy的拦截方式比较多,Object.defineProperty只有get和set5种。Proxy性能问题Proxy性能比PromiseProxy作为新标准差,从长远来看,JS引擎将继续优化ProxyThoughtsonES6ProxiesPerformanceES6Proxyperformance我的看法6.Proxy兼容性差Vue3.0放弃了对IE的支持(我原以为Vue3.0会向后兼容不兼容的浏览器,但查资料和源码后发现裕达根本没做兼容)。目前还没有完全支持ProxySolution所有拦截方式的Polyfill,有Google写的proxy-polyfill只支持get/set/apply/construct四种拦截方式多说ES7中实现的装饰器相当于设计模式中的装饰器模式。如果简单区分Proxy和Decorator的使用场景,可以概括为:Proxy的核心作用是控制外部对代理内部的访问,Decorator的核心作用是增强被装饰的人。