首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >代理构造函数和反射之间有什么区别?

代理构造函数和反射之间有什么区别?
EN

Stack Overflow用户
提问于 2016-08-27 09:51:59
回答 2查看 4.4K关注 0票数 17

反省代理之间有什么显著差异吗?

从文档中可以看出,它们似乎具有几乎相同的功能,除了:

  • 反映当时只能指定一个陷阱。
  • 代理是可撤销
  • 代理是构造函数。

如果上面的清单总结了所有的差异,那么两者都有什么理由呢?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-08-27 11:18:52

反射和代理有完全不同的目的和不同的功能。

MDN以这种方式描述代理。

Proxy对象用于定义基本操作(例如属性查找、赋值、枚举、函数调用等)的自定义行为。

并以这种方式思考

反射是一个内置对象,它为可拦截的JavaScript操作提供方法。这些方法与代理处理程序的方法相同。

我意识到你可能已经读过了,所以我会用一个例子来进一步解释。

假设你有一个对象:

代码语言:javascript
复制
const obj = {
  a: 'foo',
  b: 'bar',
};

您可以使用属性访问器访问属性a,如下所示:

代码语言:javascript
复制
console.log(obj.a); // 'foo'

您可以使用Reflect.get()方法进行同样的操作:

代码语言:javascript
复制
console.log(Reflect.get(obj, 'a')); // 'foo'

还可以使用代理构造函数创建该对象的代理。我们将使用get处理程序来拦截所有属性查找。

代码语言:javascript
复制
const proxy = new Proxy(obj, {
  get(target, property) {
    return property in target ? target[property] : 'default';
  },
});

现在,使用属性访问器或Reflect.get()获取未定义的属性将导致字符串'default'

代码语言:javascript
复制
console.log(proxy.c); // 'default'
console.log(Reflect.get(proxy, 'c')); // 'default'

代理和反射可以很好地协同工作。例如,您可以使用create创建一个具有非op get处理程序的代理:

代码语言:javascript
复制
new Proxy(obj, {
  get: Reflect.get,
});
票数 26
EN

Stack Overflow用户

发布于 2022-03-19 03:47:14

Proxy是一个对象的包装器,它将对对象的操作转发给对象,可以选择捕获其中的一些操作。高级代理对象允许您创建一个对象,该对象可以用来代替原始对象,但可以重新定义基本的对象操作,如获取、设置和定义属性。

Reflect API是用来补充代理的。内部方法如[[Get]][[Set]]等都是规范的,不能直接调用.更高级的Reflect对象使这在某种程度上成为可能。

因此,Proxy是一个包装器,可用于拦截对象上的基本操作(如[[Get]][[Set]]),而Reflect为这些基本操作(如[[Get]][[Set]])提供了最小的包装器,这样我们就可以直接调用它们(通常是从陷阱内部)。

对于每一个可由Proxy标记的内部方法,在Reflect中都有相应的方法,其名称和参数与代理陷阱相同。(!Important)

让我们看看这个例子,来演示它是如何有用的。

代码语言:javascript
复制
let user = {
  _name: "Guest",
  get name() {
    return this._name;
  }
};

let userProxy = new Proxy(user, {
  get(target, prop, receiver) {
    return Reflect.get(target, prop, receiver);
    // return target[prop];
  }
});

alert(userProxy.name); // Guest

在上面的示例中,在get陷阱中,return Reflect.get(target, prop, receiver);return target[prop];都将打印相同的输出(Guest)。

让我们以一个稍微复杂一些的例子来说明为什么Reflect.get更好,为什么get/set有第三个参数receiver

让我们创建一个对象admin,它继承自user

代码语言:javascript
复制
let user = {
  _name: "Guest",
  get name() {
    return this._name;
  }
};

let userProxy = new Proxy(user, {
  get(target, prop, receiver) {
    return target[prop]; // (*) target = user
  }
});

let admin = {
  __proto__: userProxy,
  _name: "Admin"
};

// Expected: Admin
alert(admin.name); // outputs: Guest (?!?)

阅读相关的admin.name应该返回"Admin",而不是"Guest"

问题实际上是在代理中,在行(*)中。

  1. 当我们阅读admin.name时,由于admin对象本身没有这样的属性,所以搜索就会找到它的原型。
  2. 原型为userProxy
  3. 当从代理读取name属性时,它的高级get陷阱触发并从原始对象返回它,并在行(*)中以target[prop]形式返回。对target[prop]的调用,当prop是一个getter时,在上下文this=target中运行其代码。因此,结果是this._name从原来的对象target,也就是:来自于user

要解决这个问题,我们需要将正确的this传递给getter。receiver,get陷阱的第三个参数使正确的this被传递给一个getter (在我们的例子中是admin)。对于一个常规函数,我们可以使用call/apply来绑定this值,但是我们不能对getter这样做,因为它不是called,而是访问的。

这是Reflect有用的地方。请记住,对于每一个内部方法,都是由Proxy标记的,在Reflect中有一个对应的方法,其名称和参数与代理陷阱相同。

代码语言:javascript
复制
let user = {
  _name: "Guest",
  get name() {
    return this._name;
  }
};

let userProxy = new Proxy(user, {
  get(target, prop, receiver) { // receiver = admin
    return Reflect.get(target, prop, receiver); // (*)
  }
});


let admin = {
  __proto__: userProxy,
  _name: "Admin"
};

alert(admin.name); // Admin

有关详细解释,请参阅Ilya:代理和反映的这篇精彩文章。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39179743

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档