关于Vue3 中的数据响应式功能,我们大家应该都知道,它是通过 ES6的代理模式——Proxy 对象实现的,今天我们来简单认识下何为 Proxy 对象。
Proxy 的定义
Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。
proxy
修改的是程序默认形为,就形同于在编程语言层面上做修改,属于元编程(meta
programming
),即对编程语言进行编程。
- 元编程(英语:Metaprogramming,又译超编程,是指某类计算机程序的编写,这类计算机程序编写或者操纵其它程序(或者自身)作为它们的数据,或者在运行时完成部分本应在编译时完成的工作.
Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。
Proxy 的基本语法
ES6 原生提供 Proxy 构造函数,用来生成 Proxy 实例。
var proxy = new Proxy(target, handler);
- target: 要使用
Proxy
包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。 - handler: 一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理
proxy
的行为。
Proxy 使用示例
下面是关于 Proxy 使用的一个基本示例:
const person = { name: "superMan", }; const proxy = new Proxy(man, { get(target, property, receiver) { console.log(`正在获取 ${property} 属性`) return target[property]; }, }); console.log(proxy.name); console.log(proxy.age);
在以上示例中, Proxy 构造函数接受 person
对象为代理目标,创建了一个代理对象。在创建代理对象时,我们定义了一个 get 捕获器,用于捕获代理目标属性读取的操作。 捕获器的作用就是用于拦截用户对目标对象属性读取的相关操作,在这些操作传播到目标对象之前,会先调用对应的捕获器函数,从而拦截并修改相应的行为。
在设置了 get 捕获器之后,当成功运行以上的示例代码,控制台会输出以下结果:
正在获取 name 属性 superman 正在读取 age 属性 undefined
通过观察以上输出结果,我们可以发现 get 捕获器 不仅可以拦截已知属性的读取操作,也可以拦截未知属性的读取操作。
Proxy 实例当做原型对象
Proxy 实例也可以作为其他对象的原型对象:
var proxy = new Proxy({}, { get: function(target, property) { return 35; } }); let obj = Object.create(proxy); obj.time // 35
上面代码中,proxy
对象是obj
对象的原型,obj
对象本身并没有time
属性,所以根据原型链,会在proxy
对象上读取该属性,导致被拦截。
Proxy 实例的方法
在创建 Proxy 对象时,除了定义 get 捕获器 之外,我们还可以定义其他的捕获器,比如 set、apply 、 has或者 deleteProperty 等。
get()
get
方法用于拦截某个属性的读取操作,可以接受三个参数,依次为目标对象、属性名和 proxy 实例本身(严格地说,是操作行为所针对的对象),其中最后一个参数可选。
set()
set
方法用来拦截某个属性的赋值操作,可以接受四个参数,依次为目标对象、属性名、属性值和 Proxy 实例本身,其中最后一个参数可选。
apply()
apply
方法拦截函数的调用、call
和apply
操作。
apply
方法可以接受三个参数,分别是目标对象、目标对象的上下文对象(this
)和目标对象的参数数组。
has()
has
方法用来拦截HasProperty
操作,即判断对象是否具有某个属性时,这个方法会生效。典型的操作就是in
运算符。
has
方法可以接受两个参数,分别是目标对象、需查询的属性名。
deleteProperty()
deleteProperty
方法用于拦截delete
操作,如果这个方法抛出错误或者返回false
,当前属性就无法被delete
命令删除。
defineProperty()
defineProperty
方法拦截了Object.defineProperty
操作。
总结
Proxy就是拦截层,你给出被拦截的对象,外界访问这个对象必须先通过拦截层,即访问Proxy的实例对象。通过Proxy为外界访问进行过滤和改写,如赋值时需满足某些条件。
学习有趣的知识,结识有趣的朋友,塑造有趣的灵魂!
知识与技能并重,内力和外功兼修,理论和实践两手都要抓、两手都要硬!