hal*_*bra 8 javascript reflection ecmascript-6 es6-proxy
从记录的内容来看,它们似乎具有几乎相同的功能,除了:
如果上面的列表总结了所有差异,那么两者的理由是什么?
Mic*_*ski 11
Reflect和Proxy具有完全不同的用途和不同的功能.
该
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)
Proxy是一个对象的包装器,它将对其进行的操作转发给该对象,并可选择捕获其中的一些操作。\xc2\xa0Proxy\xc2\xa0 对象允许您创建一个可用于代替原始对象的对象,但它可能会重新定义基本的对象操作,例如获取、设置和定义属性。
ReflectAPI 旨在补充 Proxy。[[Get]]\xc2\xa0 、\xc2\xa0 \xc2\xa0等内部方法[[Set]]仅规范,不能直接调用 \xe2\x80\x99 。\xc2\xa0 Reflect\xc2\xa0 对象使这在某种程度上成为可能。
包装器也是如此Proxy,它可用于拦截对象上的[[Get]]and\xc2\xa0等基本操作,而为我们提供了围绕这些基本操作(如and\xc2\xa0)的最小包装器,以便我们可以直接调用它们(通常从陷阱内部) 。[[Set]]Reflect[[Get]][[Set]]
------------ Reflect如何补充Proxy ------------
\n对于每个可由\xc2\xa0 捕获的内部方法Proxy,\xe2\x80\x99 在\xc2\xa0 中有一个相应的方法Reflect,其名称和参数与\xc2\xa0Proxy\xc2\xa0trap 相同。(!重要的)
让我们看一下这个示例来演示它的用途。
\nlet 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\nRun Code Online (Sandbox Code Playgroud)\n在上面的示例中,在get陷阱内,return Reflect.get(target, prop, receiver);和return target[prop];都会打印相同的输出 ( Guest)。
让我们举一个稍微复杂一点的例子来演示为什么Reflect.get更好以及为什么 \xc2\xa0 get/set\xc2\xa0 有第三个参数 \xc2\xa0 receiver。
让我们创建一个admin继承自的对象user:
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 (?!?)\nRun Code Online (Sandbox Code Playgroud)\n读取\xc2\xa0 admin.name\xc2\xa0 应该返回\xc2\xa0 "Admin",而不是\xc2\xa0 "Guest"!
问题实际上出在代理的 \xc2\xa0 行中(*)。
admin.name,由于 \xc2\xa0 admin\xc2\xa0 对象没有 \xe2\x80\x99t 拥有这样的属性,因此搜索将转到其原型。userProxy。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。为了解决这个问题,我们需要将正确的值传递this给 getter。receiver,\xc2\xa0get\xc2\xa0trap 的第三个参数保留正确的\xc2\xa0 this\xc2\xa0 传递给 getter(在我们的例子中是 \xe2\x80\x99s\xc2\xa0admin)。对于常规函数,我们可以使用\xc2\xa0call/apply来绑定this值,但我们不能这样做,因为getter它不是called,只是访问的。
这就是Reflect有用的地方。请记住,对于每个可由\xc2\xa0 捕获的内部方法,Proxy\xe2\x80\x99 在\xc2\xa0 中有一个相应的方法Reflect,其名称和参数与\xc2\xa0Proxy\xc2\xa0trap 相同。
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\nRun Code Online (Sandbox Code Playgroud)\n详细解释请参考 Ilya Kantor 的这篇精彩文章:Proxy and Reflect
\n| 归档时间: |
|
| 查看次数: |
1729 次 |
| 最近记录: |