【问题标题】:ES6 "universal" proxyES6“通用”代理
【发布时间】:2017-02-28 19:49:11
【问题描述】:

我想了解为什么无法使用 ES6 创建“通用”转发代理。 “通用”是指代理目标可以是具有相同代理声明(构造函数 + 处理程序)的任何类型的非原始值(包括函数)。

案例一:

var o = function myCtor() {}

var p = new Proxy({}, {
    construct: function(target, ...args) {
        return Reflect.construct(o, ...args);
    }
});

console.log(new p); // TypeError: p2 is not a constructor

案例2:

var o = {}

var p = new Proxy(function() {}, {
    ownKeys: function(target) {
        return Reflect.ownKeys(o);
    }
});

console.log(Object.keys(p)); // TypeError: 'ownKeys' on proxy: trap result did not include 'arguments'

当我使用 function(){} 作为代理目标(而不是 {})时,案例 1 可以正常工作,但是之后,案例 2 不再有效。

感谢您的帮助。

【问题讨论】:

  • 函数具有以下属性:lengthnamearguments, caller` 和 prototype。似乎包装函数的代理期望 arguments 在键列表中。可能还有其他人,但解决这个问题就像return ['arguments', ...Reflect.ownKeys(o)] 一样简单。
  • @FelixKling 骗子! :)
  • developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…“结果列表必须包含目标对象所有不可配置的自身属性的键。”
  • 您观察到的行为是代理在 ECMAScript 中保留 Invariants of the Essential Internal Methods 的结果。
  • @FelixKling 你能解释为什么“结果列表必须包含目标对象的所有不可配置的自身属性的键。”吗?我想使用代理通过使用数组索引映射到代理处理程序中的字段名称来使数组(目标)看起来是一个对象。我当然没有理由让 ownKeys 方法将长度作为属性返回,为什么 ECMA 脚本有这个要求?我希望 ownKeys() 简单地从字段/索引映射中返回字段名称列表(不必包含“长度” - 除非这是其中一个字段的名称)。

标签: javascript ecmascript-6 es6-proxy


【解决方案1】:

一个 Proxy 实例是一个目标,所以比较 (proxy instanceof == target.constructor) 将始终返回 true。所以对代理进行操作必须像目标对象类型一样。

  1. 情况1,Proxy返回一个Object实例,是一个实例而不是is-a Function实例,所以不能用new关键字调用。所以你可以通过传递一个Function实例来通过测试而是。

     var o = function myCtor() {}
    
        var p = new Proxy(function(){}, {
            construct: function(target, ...args) {
                return Reflect.construct(o, ...args);
            }
        });
    
        console.log(new p);
    
  2. 在情况 2 中,因为 Function 具有不可配置的 prototype 属性,并且代理必须是 is-a Function 实例。所以通过测试 handler.ownKeys() 必须存在 prototype 属性名称。并且任何定义为Object.defineProperty(foo, 'foo', {configurable: false}) handler.ownkeys() 的属性都必须存在。例如:必须包含可枚举的名称,包括foo

    var o = {prototype:{}}
    
    var p = new Proxy(function() {}, {
        ownKeys: function(target) {
            return Reflect.ownKeys(o);
        }
    });
    
    console.log(Object.keys(p));
    

代理的例子很多here,你可以自己尝尝这些例子。尝过之后你还可以深入看看代理文档。

【讨论】:

  • 代理可以拦截任何对象,函数也是一个实例Function对象。但是它们有一些不同的用法。在函数方式中代理创建必须作为函数调用,在对象方式中代理必须用作对象。等等
  • 函数是对象。你也可以edit你的答案。
猜你喜欢
  • 2023-03-11
  • 2017-12-30
  • 1970-01-01
  • 1970-01-01
  • 2020-08-30
  • 1970-01-01
  • 1970-01-01
  • 2017-04-19
  • 2019-04-05
相关资源
最近更新 更多