问题
Reflect.get三个参数target, key, receiver,前两个好理解,第三个是什么意思呢?哪些场景下会用到呢?本文尝试解释下这个问题。
解释
首先搬出MDN对应Reflect.get第三个参数recevier的解释:
Reflect(target, key, recevier)中,如果
target对象中指定了getter,receiver则为getter调用时的this值。
我们先定一个原始对象obj:
            
            
              js
              
              
            
          
          const obj = {
    hello: 1
}根据MDN的描述,receiver是用来指定原始对象中getter的this 。因此obj需要增加一个getter属性world,同时在getter方法使用this。
            
            
              js
              
              
            
          
          const obj = {
    hello: 1,
    get world() {
        return this.hello
    }
}
console.log(obj.world) // 1这样一个符合条件的原始对象例子有了。访问obj.world输出1。
那下面的代码呢?
            
            
              js
              
              
            
          
          const obj2 = {
    hello: 2
}
console.log(Reflect.get(obj, 'world', obj2)); // 2结果返回的是2。这里解释下原因:
- 当前Reflect.get的receiver为obj2,obj2有一个属性hello为2;
- 根据MDN的描述,receiver为getter调用的this值,因此obj中getter属性的this指向obj2。
- 当读取obj的world属性时,返回this.hello,因此返回的为obj2的hello值。
使用场景
通常在Proxy中我们如下返回原始对象的属性值:
            
            
              js
              
              
            
          
          const pObj = new Proxy(obj, {
    get(target, key, receiver) {
        console.log('Proxy key:', key)
        return target[key]
    }
})
pObj.world; // 读取代理对象的world属性
// 输出
// Proxy key: world因为读取了pObj的属性world,因此会进入到get方法,所以输出如上。
当然我们也可以通过Reflect.get返回属性值:
            
            
              js
              
              
            
          
          const pObj = new Proxy(obj, {
    get(target, key, receiver) {
        console.log('Proxy key:', key)
        return Reflect.get(target, key, receiver)
    }
})
pObj.world; // 读取代理对象的world属性
// 输出
// Proxy key: world
// Proxy key: hello通过Reflect.get的调用,多输出了一行hello。原因如下:
- 首先得知道下Proxy中的get方法中也有一个reciever,根据MDN的描述。它表示的就是当前的Proxy对象pObj。
- 因此Reflect.get(target, key, receiver)等价于Reflect.get(target, key, pObj),读取world的时候的时候,返回this.hello,当前的this又指代的是pObj,因此读取了pObj.hello。
- pObj.hello的读取再次进入了代理对象的- get方法中,因此输出了第二行的- hello。
通过上面两种方式的对比,可以知道,如果使用target[key]的方法返回属性值,我们无法拦截到this.hello的读取操作;而通过Reflect.get则可以。
总结
- Reflect.get(target, key, receiver)方法中,- receiver指代- target对象中- getter属性的this值。
- 相关代码:github.com/wdskuki/js-...