用 ES6 代理替换原型时超出最大调用堆栈大小

Maximum call stack size exceeded when replacing prototype with ES6 Proxy

我有一个打字稿class装饰器

export function Profile(config: ProfilerConfig): ClassDecorator {
  return function <TFunction extends Function> (target: TFunction) {
    logToConsole = config.logToConsole || false;
    Object.setPrototypeOf(
      target.prototype,
      new Proxy(target.prototype , handler)
    );
  };
}

我正在尝试用目标原型的代理替换原型,我得到了

ERROR RangeError: Maximum call stack size exceeded

但我没有看到任何明显的递归。当我使用

target.prototype = new Proxy(target.prototype , handler)

这不会发生。有什么想法吗?

target.prototype = new Proxy(target.prototype , handler)

这会将 targetprototype 设置为其自身的代理。

Object.setPrototypeOf(
  target.prototype,
  new Proxy(target.prototype , handler)
);

这会将 target.prototypeprototype 设置为 target.prototype 的代理。然后你有一个循环依赖:Object.getPrototypeOf(target.prototype) == proxy(target.prototype),所以当 JavaScript 试图遍历原型链时,它将陷入一个无限循环,一遍又一遍地调用代理处理程序。


我认为 Object.setPrototypeOf() 无论如何在这里没有任何意义。此函数旨在设置 实例 的原型。您似乎在尝试设置构造函数的原型,即 new constructor 创建实例时将从中继承的 constructor.prototype 对象。您需要像在第一个代码段中那样直接分配构造函数的 prototype

此处超过最大调用堆栈:

Object.setPrototypeOf( target.prototype, new Proxy(target.prototype , handler) );

让我们看看这里发生了什么:您想向 target.prototype 添加代理。我不确定,是否可以,因为 MDN 对代理目标的描述:

A target object to wrap with Proxy. It can be any sort of object, including a native array, a function, or even another proxy.

但是对象的原型是 any sort of object,所以假设您可以做到。

然后,您尝试添加代理原型作为目标原型的原型(抱歉)。像这样带圆圈的链接是超出堆栈的好方法。所以就在这里。

我认为一些简单 getter 的 JS 方式解决方法会对您有很大帮助:

Object.defineProperty(proto, 'foo', get: function() { ...} );

这不是特定于 target.prototype,任何对象都会发生:

const o = {};
Object.setPrototypeOf(o, new Proxy(o, {}));
o.property;

您认为 property 来自哪里。它可以是 o 自己的 属性,也可以从其原型继承:代理说它不是自己的 属性,但它可以从其原型继承......这让我们陷入了递归 get 访问的困境。您可以尝试在您的代理处理程序上为此提供一个陷阱,您可以使用它来记录或调试递归。

请注意,Object.setPrototypeOf(o, o) 会抛出一个异常来禁止循环继承链,但代理会绕过它。