2016-12-01 46 views
1

我想使用代理创建动态的不可配置属性。我尝试这样做:使用代理创建动态的不可配置属性

const proxy = new Proxy({}, { 
 
    getOwnPropertyDescriptor() { 
 
    return { 
 
     configurable: false, 
 
     enumerable: false, 
 
    }; 
 
    }, 
 
}); 
 

 
console.log(Reflect.getOwnPropertyDescriptor(proxy, 'test'));

但我发现了一个错误:

TypeError: 'getOwnPropertyDescriptor' on proxy: trap reported non-configurability for property 'test' which is either non-existant or configurable in the proxy target

MDN说:

A property cannot be reported as non-configurable, if it does not exists as an own property of the target object or if it exists as a configurable own property of the target object.

但它并不能说明什么这背后的推理。

有没有解决此错误的方法?

回答

7

不是。这是由于所希望的不变性,即如果您在对象中观察到不可配置的属性,它不会神奇地消失。如果它也是不可写的,它的价值不能改变。

如果你不能依靠这个,getOwnPropertyDescriptor基本上是无用的。

强制您不要使用不可配置的属性,或者在目标中定义它们,这意味着您不会违反此不变量,因为不变量通过构造持有目标。也就是说,ECMAScript不允许您以打破这些不变式的方式使用代理自定义设置。

Some of the internal method invariants defined in 6.1.7.3 are essential integrity invariants. These invariants are explicitly enforced by the proxy object internal methods specified in this section. An ECMAScript implementation must be robust in the presence of all possible invariant violations.

因此,要么将属性报告为可配置的,要么在目标中定义不可配置的属性。

如果你想要动态属性,我建议只是说谎的属性是可配置的。然后添加一个defineProperty陷阱,它返回false,有效地防止重新定义。

+0

很好的解释,谢谢。你如何看待我的解决方案(发布为自己的答案)?是否有任何我没有想到的副作用? –

+0

@Gothdo是的,这应该正常工作。你可能会遇到像另一个代理或不可扩展对象那样的更一般的目标,但如果你使用'{}'而不把它暴露给其他代码,我没有看到任何问题。 – Oriol

0

看来,如果在getOwnPropertyDescriptor陷阱里面,我在返回描述符之前在目标对象上定义该属性,它工作正常。

const proxy = new Proxy({}, { 
 
    getOwnPropertyDescriptor(target, property) { 
 
    const descriptor = { 
 
     configurable: false, 
 
     enumerable: false, 
 
    }; 
 
    Reflect.defineProperty(target, property, descriptor); 
 
    return descriptor; 
 
    }, 
 
}); 
 

 
console.log(Reflect.getOwnPropertyDescriptor(proxy, 'test'));

副作用是(显然)已创建的属性,不能被删除(因为它是不可配置的),这意味着,例如我以后不能报告为不存在的,但在我的情况下,这并不重要。