前言
最近在看 vue3 Reactive
部分的 源码,在使用 Proxy
创建代理实现拦截中,当我们读取目标对象上的属性时,也就是在 createGetter
方法里面使用了 Reflect.get
,使用它比 tarGET@[key]
的优势在哪里呢?
我们先去 vue3官网 看下。它提到,使用 Reflect
是为了解决 this
的问题。哦,原来是这样哈。下面我们先了解下 Reflect
,便于后续我们举 ? 。
了解 Reflect
我们通过 MDN文档- Reflect 知道,它是一个内置对象,和 Object
一样,提供拦截 JavaScript 操作的方法,但它包含以下几个特点:
1、它并非是构造函数,也就意味着不能通过 new运算符
将其调用。 2、它不是一个函数对象,也就是说不能当作方法来调用 3、它上面的所有的属性和方法都是静态的,和 Math
对象一样。
在这里我们也有一个疑问,它上面的方法 对应着 Object
也有一模一样的,比如 defineProperty
和 isExtensible
,但也是有区别的,比较 Reflect 和 Object 方法。
看完之后发现,Object
对象的方法中,大多返回目标对象,对于开发中我们很难确认这种结果的返回是否说明方法的成功或者失败,而在 Reflect
对象中,返回布尔值,明确告诉我们结果的成功或失败。由此可见, Reflect
方法更加严谨,使用更加明确。
Reflect.get()
此方法与从 对象 (tarGET@[key]
) 中读取属性类似,这里我们主要关注下它的第三个参数 receiver
,它可以修改属性访问中的 this
指向为传入的 receiver
对象。下面是官方解释,比较含蓄哈,下面我们举 ?。
Reflect.get
VS tarGET@[key]
差异
1、我们先做下分解动作。 创建一个 person
对象,在里面指定了 getter
,并使用 Proxy
将其代理生成 personProxy
代理对象,然后又声明了一个新的 p1
,使它继承自 personProxy
。
const person = { name: '张三', get FullName() { console.log(this); // { name: '张三' } return this.name; },}let personProxy = new Proxy(person, { get(target, key) { return Reflect.get(target, key) //相当于 return tarGET@[key] }, set(target, key, value) { return Reflect.set(target, key, value) }})const p1 = { __proto__: personProxy, name: '李四'}console.log(p1.FullName) // 张三
这时候我们打印 p1.FullName
发现跟我们期望的不一样,应该是 李四 才对,并且在 getter
里面获取的 this
指向的是 person
,为什么出现这种情况呢,我们分析下原因:
当我们读取 p1.FullName
时,它自身是没有该属性的,也没有指定该属性的 getter
它会找到 继承自 personProxy
中, 此时会触发 get
读取 target
里面的 key
此时的 target
目标对象为 person
,key
为 FullName
,此时 Reflect.get(target, key) === tarGET@[key]
最后就是看到打印的 p1.FullName
为 张三
这个时候,我们用到了 Reflect.get
里面的第三个参数 receiver
。它可以修改属性访问中的 this
指向为传入的 receiver
对象,而该对象 就是我们的调用者 p1
。
const person = { name: '张三', get Fullname() { console.log(this); // { name: '李四' } return this.name; },}let personProxy = new Proxy(person, { get(target, key, receiver) { return Reflect.get(target, key, receiver) }, set(target, key, value, receiver) { return Reflect.set(target, key, value, receiver) }})const p1 = { __proto__: personProxy, name: '李四'}console.log(p1.Fullname) // 李四
总结
看到这里相信大家都已经明白了,我们再总结下:
Reflect.get
比 tarGET@[key]
的优势在于 receiver
参数
它可以修改属性访问中的 this
指向为传入的 receiver
对象,即调用者
原文:https://juejin.cn/post/7101084596053213215