前言
最近在看 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.getVS 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对象,即调用者