JavaScript 代理目标对象与 属性 描述符冲突
JavaScript Proxy target object conflicts with property descriptors
我正在创建一个虚拟化对象,它使用规则引擎延迟构建其属性,作为一种跳过计算从未读取的值的技术。为此,我使用了 Proxy
。代理似乎在访问转发和虚拟化方面起到了双重作用;就我而言,我主要关心后者,而不是前者。
我遇到的问题与尝试在代理中实施 getOwnPropertyDescriptor
陷阱有关。这样做时出现错误:
TypeError: 'getOwnPropertyDescriptor' on proxy: trap returned descriptor for property 'foo' that is incompatible with the existing property in the proxy target
因为我实际上并没有将请求转发到包装对象,所以我一直在使用 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');
代理对象类似于具有只读属性的对象,不能扩展或具有任何其他类似的幻想。我尝试使用冻结且不可扩展的对象,但我仍然被告知 属性 描述符不兼容。
当我尝试使用非冻结对象作为代理目标时,出现不同类型的错误:
TypeError: 'getOwnPropertyDescriptor' on proxy: trap reported non-configurability for property 'foo' which is either non-existent or configurable in the proxy target
我在这里做错了什么?有什么方法可以让我的代理展示不可配置性?
您可能想查阅 invariants 的 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.
由于您的 target
是一个冻结的空对象,因此您的 handler.getOwnPropertyDescriptor()
陷阱的唯一有效 return 值是 undefined
。
不过,要解决根本问题,请在尝试访问时延迟初始化 属性 描述符:
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'));
您可以针对每个方法陷阱遵循此模式,通过延迟初始化访问的任何属性来抢占对您的 dummyObj
不需要的突变。
我正在创建一个虚拟化对象,它使用规则引擎延迟构建其属性,作为一种跳过计算从未读取的值的技术。为此,我使用了 Proxy
。代理似乎在访问转发和虚拟化方面起到了双重作用;就我而言,我主要关心后者,而不是前者。
我遇到的问题与尝试在代理中实施 getOwnPropertyDescriptor
陷阱有关。这样做时出现错误:
TypeError: 'getOwnPropertyDescriptor' on proxy: trap returned descriptor for property 'foo' that is incompatible with the existing property in the proxy target
因为我实际上并没有将请求转发到包装对象,所以我一直在使用 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');
代理对象类似于具有只读属性的对象,不能扩展或具有任何其他类似的幻想。我尝试使用冻结且不可扩展的对象,但我仍然被告知 属性 描述符不兼容。
当我尝试使用非冻结对象作为代理目标时,出现不同类型的错误:
TypeError: 'getOwnPropertyDescriptor' on proxy: trap reported non-configurability for property 'foo' which is either non-existent or configurable in the proxy target
我在这里做错了什么?有什么方法可以让我的代理展示不可配置性?
您可能想查阅 invariants 的 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.
由于您的 target
是一个冻结的空对象,因此您的 handler.getOwnPropertyDescriptor()
陷阱的唯一有效 return 值是 undefined
。
不过,要解决根本问题,请在尝试访问时延迟初始化 属性 描述符:
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'));
您可以针对每个方法陷阱遵循此模式,通过延迟初始化访问的任何属性来抢占对您的 dummyObj
不需要的突变。