Reflect.get 与 target[key]的区别

213 阅读2分钟

问题引出

const obj = {
    name: '张三',
    age: 3,
    get value() {
        return this.name
    }
}

const handler = {
    get(target, key, receiver) {
        return target[key]
    }
}

const p = new Proxy(obj, handler)
const children = {
    name: '李四',
    age: 20
}
Object.setPrototypeOf(children, p)
console.log(children.value); // 输出的chileren.value 的值为 张三

在这里,我们使用Proxy去代理 obj 对象, 然后创建一个children 对象, 并让children 对象的原型对象指向 代理对象p ,当我们去访问children.value的时候,由于children自身没有value属性,那么他就会顺着原型链上去找, 找到 p , 读取 p.value ,由于 p代理了 obj , 就会调用handler 中的get 方法 , 返回target[key], 也就是 obj[value], 返回obj.name,得到的值自然也就是张三。

那么问题来了, 如果我们想要得到的值不是张三, 而是 chileren 自身的name属性, 也就是 李四, 这要怎么做呢?

引入Reflect.get

我们可以去MDN 查看一下对此方法的说明: Reflect.get()

Reflect.get(target, propertyKey[, receiver])

Reflect.get()  方法与从 对象 (target[propertyKey]) 中读取属性类似,但它是通过一个函数执行来操作的。

  • target 需要取值的目标对象

  • propertyKey 需要获取的值的键值

  • receiver 如果target对象中指定了getterreceiver则为getter调用时的this值。

重点在于最后一个, 对 receiver的描述 , 如果target对象中指定了getter,receiver则为getter调用时的this值。这样看起来非常抽象, 我们不妨通过代码来解释一下这句话

const obj = {
    name: '张三',
    age: 3,
    get value(){
        console.log(this === children,"this === p");  // true 
        return this.name
    }
}

const handler = {
    get(target,key,receiver){
        return Reflect.get(target,key,receiver)  // 此处做了修改
    }
}

const p = new Proxy(obj,handler)
const children = {
    name: '李四',
    age: 20
}
Object.setPrototypeOf(children,p)   
console.log(children.value);   // 李四

上述代码中,我们把 return target[key]更改为了 Reflect.get(target,key,receiver),我们为obj指定了getter, 也就是 get value(){...} , 那么getter中的this就变为了receiver

关于为什么receiver不是proxy而是children

我们可以看MDN当中对receiver的描述 handler.get() | MDN

  • target 目标对象。
  • property 被获取的属性名。
  • receiver Proxy 或者继承 Proxy 的对象
  • 我们在前面通过Object.setPrototypeOf(children,p)使得children 继承了Proxy对象, 那么自然的, receiver 就指向 children