descriptors and not only own properties gotcha
Actually simplifying as proposal: does everyone agree that if a descriptor.[[Value]] is own property no further checks on inherited [[Get]] and [[Set]], or generally speaking Accessor Property related checks, should be made ?
This would already fix the Object.prototype.get
or .set
case since I
believe nobody ever used an inherited value
property on purpose for
descriptors ... or is it?
It will keep enumerable
and writable
still potentially problematic but
at least the following code would never fail:
Object.prototype.get = function () {}; Object.defineProperty(
Object.prototype, 'toString', Object.getOwnPropertyDescriptor(
Object.prototype, 'toString' ) );
Thanks again for any sort of outcome (or clarification on when and if this will ever be fixed)
On Dec 17, 2014, at 10:30 AM, Andrea Giammarchi wrote:
Actually simplifying as proposal: does everyone agree that if a descriptor.[[Value]] is own property no further checks on inherited [[Get]] and [[Set]], or generally speaking Accessor Property related checks, should be made ?
This would already fix the
Object.prototype.get
or.set
case since I believe nobody ever used an inheritedvalue
property on purpose for descriptors ... or is it?It will keep
enumerable
andwritable
still potentially problematic but at least the following code would never fail:
Object.prototype.get = function () {}; Object.defineProperty( Object.prototype, 'toString', Object.getOwnPropertyDescriptor( Object.prototype, 'toString' ) );
Thanks again for any sort of outcome (or clarification on when and if this will ever be fixed)
I'm not sure what you are actually asking. All specified internal uses of property descriptor objets should pas through ToPropertyDescriptor (people.mozilla.org/~jorendorff/es6-draft.html#sec-topropertydescriptor ) which will throw if there is any conflict between get/set and own value/writable properties, regardless of whether they are own or inherited. (If you know of any uses of such descriptor object in the ES6 spec that don't do this validation, please file a bug).
If you want to enforce the same semantics on you ES-level uses of descriptor objects you need to write a ES level implementation of the checks performed by ToPropertyDescriptor.
I can see various ways we might improve the specified processing of property descriptor objects but those would generally be breaking changes and we would have to consider the possible impact of such changes before proceeding with them.
My main point is that everything you get from
Object.getOwnPropertyDescriptor
, beside undefined or possible abrupt
errors, will have own properties.
Even es5-shim/sham has been checking own properties for years [1] so I am pretty confident nothing will break 'cause own properties is what developers always expected and what they've always used despite specs.
Again it's clear the world can live with these possibly inherited descriptors properties but it feels very wrong on the practical level. Too bad if there won't be ever a fix [2]
[1] es-shims/es5-shim#211 now fixed
[2] would a new Descriptor({ownproperties:"only"}) instance be ever considered ?
Can we be sure nobody's ever written something like this:
function shadow(obj, props) {
var ret = Object.create(obj);
}
Oops, misfire. The rest of that:
function shadow(obj, props) {
var ret = Object.create(obj);
for (var k in props)
ret[k] = props[k]
return ret;
}
// Elsewhere...
function defineSomeProps (obj) {
var defaults = { enumerable: true, writable: true, configurable:
true };
Object.defineProperties(obj, {
foo1: shadow(defaults, { value: 'bar1' })),
foo2: shadow(defaults, { value: 'bar2' })),
foo3: shadow(defaults, { value: 'bar3' })),
// etc...
});
}
If people have a generic shadow() function that creates an object and copies properties to it (less verbosely than just using Object.create), they could be tempted to use it to create ES3-style EWC properties.
sigh ignore me I completely misread the initial email. Serves me right for skim reading and speed replying during lunch.
Yeah, that fails anyway and if you loop through a for/in and attach as own property you are moving the problem instead of actually solving it in the current state of the specs.
This is probably closer to what I meant by Descriptor
solution to improve
reliability of descriptors in possibly hostile envs.
Although it might be even easier to patch upfront defineProperty/ies if
this is a real concern for unknown libraries.
function Descriptor(obj) {
'use strict';
for(var
self = this instanceof Descriptor ?
this : Object.create(Descriptor.prototype),
hOP = Object.prototype.hasOwnProperty,
arr = [
// common
'configurable', 'enumerable',
// data
'value', 'writable',
// accessor
'get', 'set'
],
i = 0, k; i < 6; i++
) {
k = arr[i];
if (hOP.call(obj, k)) {
// no extra checks, if it's wrong
// it should fail later on
// 'cause explicitly ambiguous
self[k] = obj[k];
}
}
return self;
}
// avoid inherited properties
Object.setPrototypeOf(
Descriptor.prototype,
Object.create(null)
);
// set the constructor
Object.defineProperty(
Descriptor.prototype,
'constructor',
new Descriptor({
value: Descriptor
})
);
// and freeze its prototype
Object.freeze(Descriptor.prototype);
On Wed Dec 17 10:30:03 PST 2014, Andrea Giammarchi wrote:
This would already fix the
Object.prototype.get
or.set
case since I believe nobody ever used an inheritedvalue
property on purpose for descriptors ... or is it?
I agree that nobody will use an inherited 'value' property, however, I think the inherited 'get' or 'set' property should be weighted equally as 'value' property, despite the fact that it is not usual to do that. I don't know whether it is a bug or it is intended, the current version of ECMAScript (5.1) seems to use [[HasProperty]] instead of [[GetOwnProperty]], so the case you talked about is actually valid in the specification. My suggestion is that maybe we should change the specification from using property to using own property only.
Excerpted From ECMAScript 5.1 8.10.5
5. If the result of calling the [[HasProperty]] internal method of Obj with argument "value" is true, then
a. Let value be the result of calling the [[Get]] internal method of Obj with argument ¨Dvalue¡¬.
b. Set the [[Value]] field of desc to value.
We can change it into
5. If the result of calling the [[GetOwnProperty]] internal method of Obj with argument "value" is not undefined, then
a. Let value be the result of calling the [[Get]] internal method of Obj with argument ¨Dvalue.
b. Set the [[Value]] field of desc to value.
I believe such a change will not make a big difference (since a descriptor has only 4 properties, it is not essential to use prototyping)
This is mainly for clarification purpose since I need to handle these objects in a single place.
Reading descriptors's description: people.mozilla.org/~jorendorff/es6-draft.html#sec-property-descriptor-specification-type
and reading how descriptors are retrieved: people.mozilla.org/~jorendorff/es6-draft.html#sec-ordinarygetownproperty
I wonder if it will ever happen that inherited properties will be just ignored/dropped and descriptors made safer without being able to set properties, even by accident, on the
Object.prototype
Rationale & Examples
It looks like
getOwnPropertyDescriptor
will always return objects with own properties, making considered inheritance for descriptor not only an issue when setting them, but also when reading them.Object.prototype.get = function () {}; var descriptor = Object.getOwnPropertyDescriptor( Object.prototype, 'toString' ); // resultingo into Object { value: function, writable: true, enumerable: false, configurable: true, get: function } // note the get is inherited
How can I tell if I should accept a property without passing through
value in object || object.hasOwnProperty('get')
and similar stuff?I'd say own properties should have priority but then why are inherited properties considered at all if these cannot be overwritten without causing potential problems?
As example, that descriptor that inherits from
Object.prototype
has been retrieved via native methods,Object.getOwnPropertyDescriptor
, and it will fail through native methods.Following an example:
Thanks for any sort of outcome.
Best