Proxy semantics and Object.defineProperty
Good catch. It was not intentional to specify that normalized descriptors are necessarily complete. Actually, there are two cases to consider:
- for defineProperty, the descriptor should not be completed, for exactly the reason you show.
- for get{Own}PropertyDescriptor, in ES5 the result is always a complete descriptor, so it is not unreasonable for proxies to auto-complete any returned descriptor object.
That would indicate that defineProperty needs:
NormalizePropertyDescriptor ( Attributes ) ... 2. Let desc be the result of calling ToPropertyDescriptor(Attributes) 3. Let descObj be the result of calling FromGenericPropertyDescriptor(desc) ...
And we need a separate NormalizeAndCompletePropertyDescriptor (invoked by get{Own}PropertyDescriptor), which is similar to the above, but instead calls:
NormalizeAndCompletePropertyDescriptor ( Attributes ) ... 2. Let desc be the result of calling ToCompletePropertyDescriptor(Attributes) 3. Let descObj be the result of calling FromPropertyDescriptor(desc) ...
Did I miss anything?
2011/7/13 Jason Orendorff <jason.orendorff at gmail.com>
On Wed, Jul 13, 2011 at 10:55 AM, Tom Van Cutsem <tomvc.be at gmail.com> wrote:
Good catch. It was not intentional to specify that normalized descriptors are necessarily complete. Actually, there are two cases to consider:
- for defineProperty, the descriptor should not be completed, for exactly the reason you show.
- for get{Own}PropertyDescriptor, in ES5 the result is always a complete descriptor, so it is not unreasonable for proxies to auto-complete any returned descriptor object.
Right, I agree. Thanks for the quick reply.
On the wiki page for Proxy semantics, harmony:proxies_semantics Object.defineProperty is specified to call NormalizePropertyDescriptor, which fills in all missing fields of the property descriptor.
This normalization makes it impossible to implement wrappers that are transparent to Object.defineProperty. I think it's a bug in the spec.
For example:
var obj = {x: 1}; var wrapper = Proxy.create({ defineProperty: function (name, desc) { Object.defineProperty(obj, name, desc); } });
// At this point obj.x is a configurable, writable data property.
// Now if we do this: Object.defineProperty(obj, "x", {value: 2}); // then obj.x is still configurable and writable afterwards.
// But if we do this: Object.defineProperty(wrapper, "x", {value: 3}); // then obj.x becomes non-configurable and non-writable, // because the proxy handler received the normalized // descriptor {configurable: false, enumerable: false, // writable: false, value: 3}.