带有Proxy类的TypeError - TypeError:代理上的'set':陷阱返回属性的truish [英] TypeError with Proxy class - TypeError: 'set' on proxy: trap returned truish for property

查看:263
本文介绍了带有Proxy类的TypeError - TypeError:代理上的'set':陷阱返回属性的truish的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用Proxy类时出现这个有趣的错误:

I am getting this fun error when using the Proxy class:

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

我有一个库,它以递归方式创建代理对象属性,其中任何非原始属性都是代理对象本身等等:

I have a library which creates proxy object properties recursively, where any non-primitive property is a Proxy object itself, etc etc.:

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







 // nodejs
 let McProxy = require('proxy-mcproxy');
 let val = McProxy.create();
 val.users = [];
 val.users = 3; // kaaaboom..error!

但是当我将users属性设置为第一次时,我在这个问题的标题中得到了错误!

but when I set the users property the first time, I get the error in title of this question!

在我上面的库代码中, mirrorCache 是检查属性是否先前已设置的方法。我想要做的就是抛出错误,即使我们不在严格模式,所以 mirrorCache 似乎是必要的,以便我自己做簿记。

In my library code above, mirrorCache is a way to check if the property has been previously set. Want I want to do, is to throw an error, even if we aren't in strict mode, so mirrorCache appears to be necessary so that I do my own bookkeeping.

也许有一种不同或更好的方式来实现我想要实现的目标?以下是我的目标:

Perhaps there is a different or better way to achieve what I want to achieve? Here are my goals:


  1. 即使不是严格模式,也要输入错误

  2. 只要开发人员重新分配属性,就会抛出错误。每个指定的属性都应该是不可变的。


推荐答案

请参阅以下9.5节。 ECMA规范中的9条:

Take a look at the following, section 9.5.9 of the ECMA spec:

http://www.ecma-international.org/ecma-262/6.0/#sec-proxy-object-internal -methods-and-internal-slots-set-pv-receiver

我很确定你会同意这一点。

A riveting read I'm sure you'll agree.

我认为两个关键行是:



  1. 让booleanTrapResult为ToBoolean(调用(陷阱,处理程序,«目标,P,V,接收器»))。


和同样深奥:



  1. 如果targetDesc未定义,然后

  1. If targetDesc is not undefined, then

a。如果IsDataDescriptor(targetDesc)和targetDesc。[[Configurable]]为false且targetDesc。[[Writable]]为false,则

a. If IsDataDescriptor(targetDesc) and targetDesc.[[Configurable]] is false and targetDesc.[[Writable]] is false, then


i 。如果SameValue(V,targetDesc。[[Value]])为false,则抛出TypeError异常。

i. If SameValue(V, targetDesc.[[Value]]) is false, throw a TypeError exception.




在NOTE部分有这样的相关评论:

There is this relevant comment in the NOTE section:


如果相应的目标对象属性是不可写,不可配置的自有数据属性,则无法将属性的值更改为与相应目标对象属性的值不同。

Cannot change the value of a property to be different from the value of the corresponding target object property if the corresponding target object property is a non-writable, non-configurable own data property.

该笔记试图将其置于英文中,但它并不表示关键细节,即步骤的时间。第9点是调用setter( trap )的位。不幸的是,它检查属性是否可写的位是第14点。因此,当执行检查时,属性确实是不可写且不可配置的。

That note tries to put it into English but it doesn't indicate the key detail, which is the timing of the steps. Point 9 is the bit where your setter (trap) gets called. Unfortunately the bit where it checks whether the property is writable is point 14. So by the time the check is performed the property is indeed non-writable and non-configurable.

解决此问题的一种方法是通过在 defineProperty 中的 configurable:true 中进行查询来配置属性。我并不完全遵循你的用例,所以我不知道这是否是一个可接受的妥协。

One way to fix this is to make the property configurable by chucking in a configurable: true in your defineProperty. I don't entirely follow your use case so I can't tell whether that would be an acceptable compromise.

我也想知道为什么你需要设置这些属性首先是不可写的。如果始终通过代理访问基础对象,那么您可以完全控制所有 set 调用。我甚至不确定你为什么需要 mirrorCache ,而不仅仅是检查属性是否已经在目标对象中。如果你不能假设这些对象将永远通过他们的代理进行访问,那么看起来你已经失去了战斗,因为属性可以在你不知道有关它的情况下进行更改。

I'm also wondering why you need to set these properties to be non-writable in the first place. If the underlying objects will always be accessed via their proxies then you have total control over all the set calls. I'm not even really sure why you need the mirrorCache rather than just checking whether the property is already in the target object. If you can't assume that the objects will always be accessed via their proxies then it would seem you've already lost the battle as properties can be changed without you ever knowing a thing about it.

这样的东西似乎接近你想要的东西:

Something like this seems close to what you want:

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;
    }
  });
};

需要更多调整才能正确使用数组但是我不清楚你会使用哪种数组方法期待支持。

It needs a bit more tweaking to work with arrays properly but I'm unclear which array methods you would expect to support.

这篇关于带有Proxy类的TypeError - TypeError:代理上的'set':陷阱返回属性的truish的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆