Proxy构造函数和Reflect有什么区别?

hal*_*bra 8 javascript reflection ecmascript-6 es6-proxy

ReflectProxy之间有什么重大区别吗?

从记录的内容来看,它们似乎具有几乎相同的功能,除了:

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

如果上面的列表总结了所有差异,那么两者的理由是什么?

Mic*_*ski 11

Reflect和Proxy具有完全不同的用途和不同的功能.

MDN以这种方式描述代理:

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

并以这种方式反思:

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

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

假设你有一个对象:

const obj = {
  a: 'foo',
  b: 'bar',
};
Run Code Online (Sandbox Code Playgroud)

您可以a使用以下属性访问器访问属性:

console.log(obj.a); // 'foo'
Run Code Online (Sandbox Code Playgroud)

您可以使用相同的Reflect.get()方法:

console.log(Reflect.get(obj, 'a')); // 'foo'
Run Code Online (Sandbox Code Playgroud)

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

const proxy = new Proxy(obj, {
  get(target, property) {
    return property in target ? target[property] : 'default';
  },
});
Run Code Online (Sandbox Code Playgroud)

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

console.log(proxy.c); // 'default'
console.log(Reflect.get(proxy, 'c')); // 'default'
Run Code Online (Sandbox Code Playgroud)

Proxy和Reflect可以很好地协同工作.例如,您可以get使用Reflect使用no-op 处理程序创建代理:

new Proxy(obj, {
  get: Reflect.get,
});
Run Code Online (Sandbox Code Playgroud)


PR7*_*PR7 9

Proxy是一个对象的包装器,它将对其进行的操作转发给该对象,并可选择捕获其中的一些操作。\xc2\xa0Proxy\xc2\xa0 对象允许您创建一个可用于代替原始对象的对象,但它可能会重新定义基本的对象操作,例如获取、设置和定义属性。

\n

代理人

\n

ReflectAPI 旨在补充 Proxy。[[Get]]\xc2\xa0 、\xc2\xa0 \xc2\xa0等内部方法[[Set]]仅规范,不能直接调用 \xe2\x80\x99 。\xc2\xa0 Reflect\xc2\xa0 对象使这在某种程度上成为可能。

\n

包装器也是如此Proxy,它可用于拦截对象上的[[Get]]and\xc2\xa0等基本操作,而为我们提供了围绕这些基本操作(如and\xc2\xa0)的最小包装器,以便我们可以直接调用它们(通常从陷阱内部) 。[[Set]]Reflect[[Get]][[Set]]

\n

------------ Reflect如何补充Proxy ------------

\n

对于每个可由\xc2\xa0 捕获的内部方法Proxy,\xe2\x80\x99 在\xc2\xa0 中有一个相应的方法Reflect,其名称和参数与\xc2\xa0Proxy\xc2\xa0trap 相同。(!重要的)

\n

让我们看一下这个示例来演示它的用途。

\n
let user = {\n  _name: "Guest",\n  get name() {\n    return this._name;\n  }\n};\n\nlet userProxy = new Proxy(user, {\n  get(target, prop, receiver) {\n    return Reflect.get(target, prop, receiver);\n    // return target[prop];\n  }\n});\n\nalert(userProxy.name); // Guest\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

让我们举一个稍微复杂一点的例子来演示为什么Reflect.get更好以及为什么 \xc2\xa0 get/set\xc2\xa0 有第三个参数 \xc2\xa0 receiver

\n

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

\n
let user = {\n  _name: "Guest",\n  get name() {\n    return this._name;\n  }\n};\n\nlet userProxy = new Proxy(user, {\n  get(target, prop, receiver) {\n    return target[prop]; // (*) target = user\n  }\n});\n\nlet admin = {\n  __proto__: userProxy,\n  _name: "Admin"\n};\n\n// Expected: Admin\nalert(admin.name); // outputs: Guest (?!?)\n
Run Code Online (Sandbox Code Playgroud)\n

读取\xc2\xa0 admin.name\xc2\xa0 应该返回\xc2\xa0 "Admin",而不是\xc2\xa0 "Guest"

\n

问题实际上出在代理的 \xc2\xa0 行中(*)

\n
    \n
  1. 当我们读取 \xc2\xa0 时admin.name,由于 \xc2\xa0 admin\xc2\xa0 对象没有 \xe2\x80\x99t 拥有这样的属性,因此搜索将转到其原型。
  2. \n
  3. 原型是\xc2\xa0 userProxy
  4. \n
  5. name当从代理读取 \xc2\xa0 \xc2\xa0 属性时,其 \xc2\xa0 get\xc2\xa0trap 会触发并将其从原始对象返回为 \xc2\xa0 target[prop]\xc2\xa0 行中的 \xc2\xa0 (*)target[prop]当 \xc2\xa0 \ propxc2\xa0 是 getter 时,对 \xc2\xa0 的调用将在上下文 \xc2\xa0 中运行其代码this=target。所以结果是\xc2\xa0 this._name\xc2\xa0from 原始对象\xc2\xa0 target,即: from\xc2\xa0 user
  6. \n
\n

为了解决这个问题,我们需要将正确的值传递this给 getter。receiver,\xc2\xa0get\xc2\xa0trap 的第三个参数保留正确的\xc2\xa0 this\xc2\xa0 传递给 getter(在我们的例子中是 \xe2\x80\x99s\xc2\xa0admin)。对于常规函数,我们可以使用\xc2\xa0call/apply来绑定this值,但我们不能这样做,因为getter它不是called,只是访问的。

\n

这就是Reflect有用的地方。请记住,对于每个可由\xc2\xa0 捕获的内部方法,Proxy\xe2\x80\x99 在\xc2\xa0 中有一个相应的方法Reflect,其名称和参数与\xc2\xa0Proxy\xc2\xa0trap 相同。

\n
let user = {\n  _name: "Guest",\n  get name() {\n    return this._name;\n  }\n};\n\nlet userProxy = new Proxy(user, {\n  get(target, prop, receiver) { // receiver = admin\n    return Reflect.get(target, prop, receiver); // (*)\n  }\n});\n\n\nlet admin = {\n  __proto__: userProxy,\n  _name: "Admin"\n};\n\nalert(admin.name); // Admin\n
Run Code Online (Sandbox Code Playgroud)\n

详细解释请参考 Ilya Kantor 的这篇精彩文章:Proxy and Reflect

\n