Proxy对象代理
# 概述
我们都知道不管是 vue2
还是 vue3
,都实现了数据和视图的响应式绑定与更新,那么两者有何区别呢?
vue2
主要是通过数据劫持的方式,通过Object.defineProperty
来通过set
和get
劫持数据,当数据发生变化上,会通知模板引擎重新渲染。本质上vue3
的实现思路没有什么不同,不过vue3
使用过Proxy
进行代理- 还有个区别就是
vue2
会默认让所有的数据具备响应式的能力,而vue3
则需要通过reactive
和ref
来声明响应式数据
# Proxy
对象
Proxy
对象用于创建一个对象的代理,从而实现对目标对象的访问拦截和修改(如属性查找、赋值、枚举和函数调用)。
- 语法:
new Proxy(target, handler)
target
: 需要代理的目标对象(可以是任何类型,包括原生对象)
handler
: 一个对象,其属性是当执行一个操作时定义代理的行为的函数。
# handler
实例方法
参照 MDN 文档,handler
可以如下 13 种方法
handler.apply()
:用于拦截函数的调用
handler.construct()
:用于拦截构造函数new
操作符的调用
handler.defineProperty()
:用于拦截对象Object.defineProperty()
操作
handler.deleteProperty()
:用于拦截对对象属性的delete
操作
handler.get()
:用于拦截对象属性的读取
handler.getOwnPropertyDescriptor()
:用于拦截Object.getOwnPropertyDescriptor()
操作
handler.getPrototypeOf()
:是一个代理方法,当读取代理对象的原型时,该方法就会被调用
handler.has()
:拦截in
操作符
handler.isExtensible()
:拦截Object.isExtensible()
操作
handler.ownKeys()
:拦截Reflect.ownKeys()
,返回一个数组;还可拦截Object.getOwnPropertyNames()
和Object.getOwnPropertySymbols()
,Object.keys()
等
handler.preventExtensions()
:拦截Object.preventExtensions()
handler.set()
: 拦截set
操作
handler.setPrototypeOf()
:拦截Object.setPrototypeOf()
# Proxy
在vue3
中的应用
vue3
在@vue/reactivity
中首先定义了BaseReactiveHandler
类,其中重新定义了get
方法,在get
方法中会调用track
方法,用于收集依赖
MutableReactiveHandler
和ReadonlyReactiveHandler
会继承BaseReactiveHandler
类,前者是用到最多的。
MutableReactiveHandler
类除了继承BaseReactiveHandler
类外,还重写了set
、deleteProperty
、has
和ownKeys
方法,在set
和deleteProperty
中会调用trigger
方法,用于触发依赖。