Hi FE !
Ai
git
前端面试题
前端小tip
  • vite
  • webpack
npm
  • vue2
  • vue3
react
GitHub
Ai
git
前端面试题
前端小tip
  • vite
  • webpack
npm
  • vue2
  • vue3
react
GitHub
  • Reflect和Proxy

Reflect和Proxy

Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法。这些方法与proxy handlers 的方法相同.

既然 作用一致 ,那么使用Reflect.get有何意义呢,

const obj = {
  foo: 'foo',
  get bar () {
    return this.foo;
  }
};
const handler = {
  get (target, key, receiver) {
    console.log(`我被读取了${key}属性`);
    return target[key];
  },
  set (target, key, val, receiver) {
    console.log(`我被设置了${key}属性, val: ${val}`);
    target[key] = val;
  }
};
const p = new Proxy(obj, handler);
p.bar; // 输出:我被读取了bar属性
// Q: 为什么读取foo属性没有被拦截

在上述代码中我们定义了一个foo属性和bar属性,其中bar属性是一个访问器属性,通过get函数 return this.foo获取得到 的,因此按理来说我们在读取bar属性时候会触发读取foo属性,也同样会被get的trap所拦截到,但实际代码运行结果并没有拦截到foo属性。这是为什么呢,答案的关键在于bar访问器里的this指向。梳理下代码运行过程:p.bar 实际上会被handler的get捕获 返回 target['bar'],而这里的target实际上就是obj,所以这时候bar访问器里的this指向obj,this.foo,实际就是obj.foo。而obj并不是proxy对象p,所以访问其foo属性并不会被拦截到。

那么如何也能触发到foo属性的拦截呢,这时候Reflect就派上用场了,有以下代码:


const obj = {
  foo: 'foo',
  get bar () {
    return this.foo;
  }
};
const handler = {
  get (target, key, receiver) {
    console.log(`我被读取了${key}属性`);
    return Reflect.get(target, key, receiver);
  },
  set (target, key, val, receiver) {
    console.log(`我被设置了${key}属性, val: ${val}`);
    return Reflect.set(target, key, val, receiver);
  }
};
const p = new Proxy(obj, handler)
p.bar; // 输出:我被读取了bar属性   我被读取了foo属性

如上面代码所示,我们能正确地触发了foo属性的拦截,其实现的关键在于Reflect.get的第三个参数receiver ,其作用就是改变this指向,在MDN里有以下描述:

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

而我们这里的receiver就是p对象,this.foo 等同于 p.foo,因此访问bar属性的 时候同样可以拦截得到。也正是因为this指向的问题,所以建议在proxy对象拦截器里的属性方法都通过Reflex.*去操作。

Edit this page
最近更新: 2025/6/27 02:24
Contributors: qdleader
qdleader
本站总访问量 129823次 | 本站访客数 12人