Proxy的好搭档 Reflect
一句话解释:用来调用对象的 基本方法
基本方法:针对ES对象的基本操作,这些基本操作在day5 vue3源码学习之proxy 与 definepropety - 掘金 (juejin.cn)有介绍。 在过去这些基本方法是不对外暴露的,我们是不能直接调用这些基本方法的。
在过去调用这些基本方法
只能通过对象的语法操作
// 使用语法调用
const obj = {
a: 11
}
// 给这个对象赋值
obj.b = 10
// 那么这个赋值操作就会间接调用底层的 [[SET]] 方法
console.log(obj) //---> {"a": 11, "b": 10 }
在现在使用ES6 的reflect方法调用
可以直接像调用静态方法一样使用那些底层方法,MDN有详细介绍: Reflect - JavaScript | MDN (mozilla.org)
// 使用 reflect形式调用
const obj = {
a: 11
}
//直接调用SET方法,这里的set与对象的基本方法[[SET]]对应
Reflect.set(obj, "b", 10)
console.log(obj) //---> {"a": 11, "b": 10 }
那这两种调用方式有什么区别呢
首先我们使用语法方式调用的时候,他往往不是直接调用的对象的基本方法,而是调用一个封装了基本方法调用的方法,如下图
来个例子:
const obj = {
a: 11,
b: 22,
get c(){
return this.a + this.b
}
}
// 扩展知识:
// 在对象中使用`get`前缀定义方法,是在 JavaScript 中使用 getter 方法的一种方式。
// Getter 方法是一种特殊的方法,用于定义对象属性的获取行为。
// 当您在对象中使用`get`前缀定义一个方法时,它会被视为该对象的一个属性,并且在访问该属性时会自动调用该方
// 法来获取属性的值。这样可以隐藏内部实现细节,并提供一种更简洁的方式来访问对象的属性。
// 相当于
// Object.defineProperty(obj, "c", {
// get: function(){
// return this.a + this.b
// }
// })
// 当把c作为属性调用时相当于调用了 getter方法
console.log(obj.c) // ---> 3
当你使用语法方式去调用 c 方法的时候相当与调用了对象的基本方法 [[GET]], 当你去看ES文档的会发现 调用 [[GET]] 方法对应的是 (propertyKey, Receiver)-> any,多了一个参数Receiver (如果调用 的对象有[[GET]]方法,那么Receiver 就是调用getter方法的this的值)。
而在我们使用 obj.c 的时候你会发现我们并不要求我们传入Receiver这个参数
在上面也介绍了,当你使用 语法方式 调用的时候,会调用一个封装过的方法,而这个方法已经帮我们准备好了这个Receiver,这个 Receiver在我们学习函数的this指向时,有这么一句话 谁调用的就指向谁,即指向 调用的对象 obj
所以调用 obj.c 的时候就相当与 返回 obj.a + obj.b,那么语法的方式调用基本方法会有一种缺陷就是无法自定义其 this指向
这时候区别就来了:
你使用语法的方式调用无法自定义其this指向,那么使用Reflect的方式就可以
const obj = {
a: 11,
b: 22,
get c(){
return this.a + this.b
}
}
// 很简单 Reflect.get(target, propertyKey, Receiver)
const obj1 = {a: 20, b:40}
const result = Reflect.get(obj, 'c', obj1)
// 当把c作为属性调用时相当于调用了 getter方法, 这时候 c中的this指向就是obj1
console.log(result) // 60 <-- obj1.a + obj1.b
为什么说是Proxy的好搭档呢
const obj = {
a: 11,
b: 22,
get c(){
return this.a + this.b
}
}
const proxyObj = new Proxy(obj,{
get: (target, key){
console.log('read', key)
// 默认操作
return target[key]
}
})
// 如果我们直接按默认的方式 return target[key] 的话你会发现
proxyObj.c // read, c
// 这就出现了问题,我们直接返回的是 target[key]那么相当远 obj.c,所以c中的this指向的是原对象obj
// 而不是代理对象proxyObj所以我们代理对象的 get 方法无法捕捉到this.a,和this.b的调用
// 而我们换成
const proxyObj = new Proxy(obj,{
get: (target, key, receiver){
console.log('read', key)
// 默认操作
return Reflect.get(target,key, receiver)
}
})
proxyObj.c
// read, c
// read, a
// read, b
// 这就可以更深沉次的监听到代理对象中的一些基本方法的调用