Vue3.0 开始用 Proxy 代替 Object.defineProperty了,这篇文章结合实例教你如何使用Proxyjavascript
本篇文章同时收录【前端知识点】中,连接直达html
JavaScript
中的 Proxy
是什么?能干什么?Vue3.0
开始为何用 Proxy
代替 Object.defineProperty
Proxy
是什么解释参考MDN,连接直达前端
const p = new Proxy(target, handler)
target
: 要使用 Proxy 包装的目标对象(能够是任何类型的对象,包括原生数组,函数,甚至另外一个代理)handler
: 对该代理对象的各类操做行为处理(为空对象的状况下,基本能够理解为是对第一个参数作的一次浅拷贝)target
就是你想要代理的对象;而 handler
是一个函数对象,其中定义了全部你想替 target
代为管理的操做对象,包含了:
handler.has(target, prop)
: in
操做符的捕捉器,拦截HasProperty操做handler.get(target, prop)
: 属性读取操做的捕捉器handler.set(target, prop, value)
: 属性设置操做的捕捉器handler.apply(target, object, args)
: 函数调用操做的捕捉器,拦截函数的调用、call和apply操做handler.getPrototypeOf()
: Object.getPrototypeOf
方法的捕捉器handler.setPrototypeOf()
: Object.setPrototypeOf
方法的捕捉器handler.isExtensible()
: Object.isExtensible
方法的捕捉器handler.preventExtensions()
: Object.preventExtensions
方法的捕捉器handler.getOwnPropertyDescriptor()
: Object.getOwnPropertyDescriptor
方法的捕捉器handler.defineProperty()
: Object.defineProperty
方法的捕捉器handler.deleteProperty()
: delete
操做符的捕捉器handler.ownKeys()
: Object.getOwnPropertyNames
方法和 Object.getOwnPropertySymbols
方法的捕捉器handler.construct()
: new 操做符的捕捉器不可配置
|| 不可写
,则该属性不可被代理,经过 Proxy
访问该属性会报错。*
标记的trap为本文都要涉及到的Proxy
能干什么?undefined
has
trap 来掩盖这个属性的存在has
方法拦截的是 hasProperty
操做,不是 hasOwnProperty
,因此 has...in
方法不判断一个属性是自身属性仍是继承的属性vue
注意: has...in
能够拦截到,for...in
拦截不到java
阻止其余人删除属性,想让调用方法的人知道该方法已经被废弃,或是想阻止其余人修改属性git
Proxy
代理起做用,必须针对 Proxy
的实例进行操做,而不是针对目标对象进行操做针对那些重度依赖资源,执行缓慢或是频繁使用的方法或接口,统计它们的使用或是性能es6
能够记录各类各样的信息而不用修改应用程序的代码或是阻塞代码执行。而且只须要在这些代码的基础上稍事修改就能够记录特性函数的执行性能
github
以上例子就是一个监听函数执行的代理,能够将其进行扩展为打点函数面试
这里面 Proxy
的 trap
为何使用 get
而不是 apply
? 答案编程
Proxy
进行封装让构造函数也可以直接进行函数调用须要解决的几个问题
xxx.xxx.xxx...
不管 undefined
出如今哪里都不能报错Proxy
的 get()
传入的参数必须是对象传统方式深层取值繁琐,利用Proxy能够简化没必要要代码
可是当 target[prop]
是 undefined
的时候,Proxy get()
的入参变成了 undefined
,但 Proxy
第一个入参必须为对象
须要对 obj 为 undefined
的时候进行特殊处理,为了可以深层取值,因此使用一个空函数进行设置拦截,利用 apply
trap 进行处理
咱们理想中的应该是,若是属性为 undefined
就返回 undefined
,但仍要支持访问下级属性,而不是抛出错误
顺着这个思路来的话,很明显当属性为 undefined
的时候也须要用 Proxy
进行特殊处理
因此咱们须要一个具备下面特性的 get()
方法
getData(undefined)() === undefined; // true getData(undefined).xxx.yyy.zzz(); // undefined
get(undefined).xxx
是否为正确的值,由于想获取值必需要执行才能拿到undefined
后面访问的属性都默认为 undefined
就行了,因此咱们须要一个代理了 undefined
后的返回对象undefined
的时候,中止执行Proxy
本质上属于元编程非破坏性数据劫持,在原对象的基础上进行了功能的衍生而又不影响原对象,符合松耦合高内聚的设计理念Object.defineProperty
经过为属性设置 getter/setter
可以完成数据的响应式,可是它并不算是实现数据的响应式的完美方案,某些状况下须要对其进行修补或者hack,这也是它的缺陷,主要表如今两个方面:
Vue.set()
从新设置添加属性的响应式push/pop/shift/unshift/splice/sort/reverse
这七个方法,其余数组方法及数组的使用则没法检测到,也没法监听数组索引的变化和长度的变动Proxy
的性能比 Promise
还差Proxy
做为新标准,从长远来看,JS 引擎会继续优化 Proxy
Vue 3.0
中放弃了对于IE的支持(觉得 Vue 3.0
中会对不兼容的浏览器进行向下兼容,可是通过查看资料和源码发现尤大压根没作兼容)Proxy
全部拦截方法的 Polyfill
方案,有一个 google
编写的 proxy-polyfill
也只支持了 get/set/apply/construct
四种拦截Decorator
,至关于设计模式中的装饰器模式。Proxy
和 Decorator
的使用场景,能够归纳为:Proxy
的核心做用是控制外界对被代理者内部的访问,Decorator
的核心做用是加强被装饰者的功能。