简体   繁体   English

JavaScript 代理目标对象与属性描述符冲突

[英]JavaScript Proxy target object conflicts with property descriptors

I'm creating a virtualized object that lazily builds its properties with a rules engine as a technique to skip calculating values that are never read.我正在创建一个虚拟化对象,它使用规则引擎懒惰地构建其属性,作为跳过计算从未读取的值的技术。 For this, I'm using a Proxy .为此,我正在使用Proxy It seems like proxies sort of serve double-duty for both access forwarding and virtualizing;代理似乎兼具访问转发和虚拟化的双重功能; in my case, I mostly care about the latter, not the former.就我而言,我主要关心后者,而不是前者。

The problem I'm having has to do with trying to implement the getOwnPropertyDescriptor trap in the proxy.我遇到的问题与尝试在代理中实现getOwnPropertyDescriptor陷阱有关。 When doing so I get the error:这样做时,我收到错误:

TypeError: 'getOwnPropertyDescriptor' on proxy: trap returned descriptor for property 'foo' that is incompatible with the existing property in the proxy target类型错误:代理上的“getOwnPropertyDescriptor”:陷阱返回的属性“foo”的描述符与代理目标中的现有属性不兼容

Because I'm not actually forwarding requests to a wrapped object, I've been using an Object.freeze({}) as the first argument passed to new Proxy(...) .因为我实际上并没有将请求转发到包装对象,所以我一直使用Object.freeze({})作为传递给new Proxy(...)的第一个参数。

function createLazyRuleEvaluator(rulesEngine, settings) {
  const dummyObj = Object.freeze({});
  Object.preventExtensions(dummyObj);

  const valueCache = new Map();

  const handlers = {
    get(baseValue, prop, target) {
      if (valueCache.has(prop)) 
        return valueCache.get(prop);

      const value = rulesEngine.resolveValue(settings, prop);
      valueCache.set(prop, value);
      return value;
    },

    getOwnPropertyDescriptor(baseValue, prop) {
      return !propIsInSettings(prop, settings) ? undefined : {
        configurable: false,
        enumerable: true,
        get() {
          return handlers.get(baseValue, prop, null);
        }
      };
    },
  };

  return new Proxy(dummyObj, handlers);
}

// This throws
Object.getOwnPropertyDescriptor(createLazyRuleEvaluator(/*...*/), 'foo');

The proxy object is meant to resemble a object with read-only properties that can't be extended or have any other such fanciness.代理对象旨在类似于具有无法扩展或具有任何其他此类幻想的只读属性的对象。 I tried using a frozen and non-extensible object, but I'm still told the property descriptor is incompatible.我尝试使用冻结且不可扩展的对象,但我仍然被告知属性描述符不兼容。

When I try using a non-frozen object as the proxy target, then I get a different type error:当我尝试使用非冻结对象作为代理目标时,我得到一个不同类型的错误:

TypeError: 'getOwnPropertyDescriptor' on proxy: trap reported non-configurability for property 'foo' which is either non-existent or configurable in the proxy target类型错误:代理上的“getOwnPropertyDescriptor”:陷阱报告了属性“foo”的不可配置性,该属性在代理目标中不存在或可配置

What am I doing wrong here?我在这里做错了什么? Is there any way I can have my proxy exhibit non-configurability?有什么办法可以让我的代理表现出不可配置性?

You might want to consult the list of invariants for handler.getOwnPropertyDescriptor() , which unfortunately includes these:您可能需要查阅handler.getOwnPropertyDescriptor()不变量列表,不幸的是,其中包括以下内容:

  • A property cannot be reported as existent, if it does not exist as an own property of the target object and the target object is not extensible.如果属性不作为目标对象的自身属性存在并且目标对象不可扩展,则该属性不能报告为存在。
  • A property cannot be reported as non-configurable, if it does not exist as an own property of the target object or if it exists as a configurable own property of the target object.如果属性不作为目标对象的自身属性存在或作为目标对象的可配置自身属性存在,则该属性不能报告为不可配置。

Since your target is a frozen, empty object, the only valid return value for your handler.getOwnPropertyDescriptor() trap is undefined .由于您的target是一个冻结的空对象,因此您的handler.getOwnPropertyDescriptor()陷阱的唯一有效返回值是undefined


To address the underlying question though, lazily initialize your property descriptors when they're attempted to be accessed:但是,为了解决潜在的问题,请在尝试访问属性描述符时延迟初始化它们:

 function createLazyRuleEvaluator(rulesEngine, settings) { const dummyObj = Object.create(null); const valueCache = new Map(); const handlers = { get(target, prop) { if (valueCache.has(prop)) return valueCache.get(prop); const value = prop + '_value'; // rulesEngine.resolveValue(settings, prop) valueCache.set(prop, value); return value; }, getOwnPropertyDescriptor(target, prop) { const descriptor = Reflect.getOwnPropertyDescriptor(target, prop) || { value: handlers.get(target, prop) }; Object.defineProperty(target, prop, descriptor); return descriptor; }, }; return new Proxy(dummyObj, handlers); } console.log(Object.getOwnPropertyDescriptor(createLazyRuleEvaluator(/*...*/), 'foo'));

You can follow this pattern for each of the method traps to preempt unwanted mutations to your dummyObj by lazily initializing any properties accessed.您可以对每个方法陷阱遵循此模式,通过延迟初始化访问的任何属性来抢占dummyObj不需要的突变。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM