descriptors and not only own properties gotcha

# Andrea Giammarchi (10 years ago)

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:

Object.defineProperty(Object.prototype, 'toString', descriptor);
Uncaught TypeError: Invalid property.  A property cannot both have
accessors and be writable or have a value, #<Object>message: "Invalid

property.  A property cannot both have accessors and be writable or have a
value, #<Object>"stack: (...)get stack: function () { [native code] }set

stack: function () { [native code] }__proto__: Error

Thanks for any sort of outcome.

Best

# Andrea Giammarchi (10 years ago)

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)

# Allen Wirfs-Brock (10 years ago)

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

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.

# Andrea Giammarchi (10 years ago)

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 ?

# Andy Earnshaw (10 years ago)

Can we be sure nobody's ever written something like this:

function shadow(obj, props) {
    var ret = Object.create(obj);
}
# Andy Earnshaw (10 years ago)

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.

# Andy Earnshaw (10 years ago)

sigh ignore me I completely misread the initial email. Serves me right for skim reading and speed replying during lunch.

# Andrea Giammarchi (10 years ago)

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

# Gary Guo (10 years ago)

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 inherited value 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)