Javascript 代理类的TypeError-TypeError:';设置';在代理上:陷阱为属性返回truish
我在使用代理类时遇到了一个有趣的错误:Javascript 代理类的TypeError-TypeError:';设置';在代理上:陷阱为属性返回truish,javascript,node.js,proxy,Javascript,Node.js,Proxy,我在使用代理类时遇到了一个有趣的错误: TypeError: 'set' on proxy: trap returned truish for property 'users' which exists in the proxy target as a non-configurable and non-writable data property with a different value 我有一个递归创建代理对象属性的库,其中任何非基本属性都是代理对象本身,等等: let mcProxy
TypeError: 'set' on proxy: trap returned truish for property 'users' which exists in the proxy target as a non-configurable and non-writable data property with a different value
我有一个递归创建代理对象属性的库,其中任何非基本属性都是代理对象本身,等等:
let mcProxy = function (target) {
const mirrorCache = {};
return new Proxy(target, {
set: function (target, property, value, receiver) {
if (mirrorCache[property]) {
throw new Error(`property ${property} has already been set`);
}
mirrorCache[property] = true;
Object.defineProperty(target, property, {
writable: false,
value: (value && typeof value === 'object') ? mcProxy(value) : value
});
return true;
}
});
};
exports.create = function (val) {
val && assert.equal(typeof val, 'object', 'val must be an object');
return mcProxy(val || {});
};
上述库代码的实际使用情况:
//bash
$ npm install proxy-mcproxy
但是,当我第一次设置用户属性时,我得到了这个问题标题中的错误 在上面我的库代码中,
mirrorCache
是一种检查属性之前是否已设置的方法。我想做的是抛出一个错误,即使我们没有处于严格的模式,所以镜像缓存似乎是必要的,这样我就可以自己记账了
也许有一种不同或更好的方式来实现我想要实现的目标?以下是我的目标:
即使不是在严格模式下也会抛出错误
在开发人员重新分配属性时抛出错误。每个指定的属性都应该是不可变的
我认为这个问题与您传递给Object.defineProperty方法的选项有关。将您的writable
选项从false
更改为true
,我认为您的问题应该得到解决
MDN对可写属性具有以下描述
可写
当且仅当与属性关联的值可以使用赋值运算符更改时,为true。
默认为false
因此从技术上讲,Object.defineProperty
是该属性的第一个设置。但这只是一个旁注。从MDN的描述中可以看出,设置为false
不允许我们通过赋值运算符更改属性=
是赋值运算符的一个示例
MDN链接:查看以下ECMA规范第9.5.9节:
一本引人入胜的书我相信你会同意的
我认为这两条关键线是:
让booleanTrapResult成为ToBoolean(调用(trap,handler,«target,P,V,Receiver»))
同样深奥的是:
如果targetDesc未定义,则
a。如果IsDataDescriptor(targetDesc)和targetDesc.[Configurable]]为false,而targetDesc.[Writable]]为false,则
一,。如果SameValue(V,targetDesc.[Value]])为false,则引发TypeError异常
注释部分中有此相关评论:
如果相应的目标对象属性是不可写、不可配置的自有数据属性,则无法将属性的值更改为与相应的目标对象属性的值不同
那张便条试图把它译成英语,但它没有指出关键的细节,即步骤的时间安排。第9点是调用setter(trap
)的位。不幸的是,它检查属性是否可写的位是第14点。因此,在执行检查时,该属性确实是不可写和不可配置的
解决此问题的一种方法是通过在defineProperty
中插入configurable:true
使属性可配置。我不完全遵循您的用例,所以我无法判断这是否是一个可接受的折衷方案
我还想知道为什么首先需要将这些属性设置为不可写。如果底层对象总是通过其代理访问,那么您可以完全控制所有set
调用。我甚至不确定为什么需要mirrorCache
,而不仅仅是检查属性是否已经在目标对象中。如果您不能假设对象总是通过其代理进行访问,那么您似乎已经输掉了这场战斗,因为属性可以在您一无所知的情况下更改
类似这样的东西似乎很接近你想要的:
let mcProxy = function (target) {
return new Proxy(target, {
set: function (target, property, value) {
if (Object.prototype.hasOwnProperty.call(target, property)) {
throw new Error(`property ${property} has already been set`);
}
target[property] = (value && typeof value === 'object') ? mcProxy(value) : value;
return true;
}
});
};
它需要更多的调整才能正确使用数组,但我不清楚您希望支持哪些数组方法。可能是的,但问题是,我希望可写为false,我希望任何属性只写一次。我做得很晚,但对于阅读本文的人来说,检查该属性是否存在,不要对其进行写入,而要使用引发错误的解决方案。proxy-mcproxy是一个很酷的小库,当我让它工作时:)回答不错,我希望你是对的,明天会验证return true
也修复了我的案例中的此错误,感谢您的详细阐述和解决方案/example@skillle
let mcProxy = function (target) {
return new Proxy(target, {
set: function (target, property, value) {
if (Object.prototype.hasOwnProperty.call(target, property)) {
throw new Error(`property ${property} has already been set`);
}
target[property] = (value && typeof value === 'object') ? mcProxy(value) : value;
return true;
}
});
};