Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is this configurable property not deletable?

Configurable properties seem to be deletable:

var o = {};
Object.defineProperty(o, 'prop', {
    configurable: true,
    value: 'val'
});
delete o.prop; // true
o.prop;        // undefined

But it doesn't work in the following case, at least on Firefox and Chrome:

var form = document.createElement('form'),
    input = document.createElement('input');
form.appendChild(input);
var elems = form.elements;
Object.getOwnPropertyDescriptor(form, 0)
      .configurable; // true <────────────────────── !!!
delete elems[0];     // false                         │
elems[0];            // input                         │
(function(){ 'use strict'; //                         V
    delete elems[0]; // TypeError: property 0 is non-configurable
})();                // and can't be deleted

But this seems to contradict the spec.

The delete operator is defined like this:

11.4.1 - The delete Operator

The production UnaryExpression : delete UnaryExpression is evaluated as follows:

  • Let ref be the result of evaluating UnaryExpression.
  • [...]
  • If IsPropertyReference(ref) is true, then
    • Return the result of calling the [[Delete]] internal method on ToObject(GetBase(ref)) providing GetReferencedName(ref) and IsStrictReference(ref) as the arguments.

So the result of using delete depends on [[Delete]]. Now let's see what [[Delete]] does:

8.12.7 - [[Delete]] (P, Throw)

When the [[Delete]] internal method of O is called with property name P and the Boolean flag Throw, the following steps are taken:

  • Let desc be the result of calling the [[GetOwnProperty]] internal method of O with property name P.
  • If desc is undefined, then return true.
  • If desc.[[Configurable]] is true, then
    • Remove the own property with name P from O.
    • Return true.
  • Else if Throw, then throw a TypeError exception.
  • Return false.

Therefore, if the property is configurable, it should be deletable.

But wait, maybe Object.getOwnPropertyDescritor is a troll and says that a property is configurable, but [[Configurable]] is false. Let's see:

15.2.3.3 - Object.getOwnPropertyDescriptor ( O, P )

When the getOwnPropertyDescriptor function is called, the following steps are taken:

  • If Type(O) is not Object throw a TypeError exception.
  • Let name be ToString(P).
  • Let desc be the result of calling the [[GetOwnProperty]] internal method of O with argument name.
  • Return the result of calling FromPropertyDescriptor(desc).

So it also uses [[GetOwnProperty]], like [[Delete]]. Maybe the troll is FromPropertyDescriptor?

8.10.4 FromPropertyDescriptor ( Desc )

When the abstract operation FromPropertyDescriptor is called with property descriptor Desc, the following steps are taken:

  • If Desc is undefined, then return undefined.
  • Let obj be the result of creating a new object as if by the expression new Object() where Object is the standard built-in constructor with that name.
  • ...
  • Call the [[DefineOwnProperty]] internal method of obj with arguments "configurable", Property Descriptor {[[Value]]: Desc.[[Configurable]], [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
  • Return obj.

So no, it is not a troll neither. The configurable property of the property descriptor is set to the [[Configurable]] value.

How is it possible, then, that a configurable property can't be deleted?

like image 705
Oriol Avatar asked Mar 14 '15 00:03

Oriol


1 Answers

Effectively, configurable properties are deletable.

But there is a big problem: that only applies to native objects, but not to host objects.

As explained in 8.6.2 - Object Internal Properties and Methods,

Host objects may support these internal properties with any implementation-dependent behaviour as long as it is consistent with the specific host object restrictions stated in this document.

For those, [[GetOwnProperty]] must behave differently:

If a property is described as a data property and it may return different values over time, then either or both of the [[Writable]] and [[Configurable]] attributes must be true even if no mechanism to change the value is exposed via the other internal methods.

In your example, form.elements is a HTMLFormControlsCollection instance defined by the HTML spec, so it's a host object.

Therefore, the situation is

  • It has a custom [[GetOwnProperty]] which says that the property '0' is configurable because its value may change.
  • It also has a custom [[Delete]] which doesn't delete the property, even if [[GetOwnProperty]] says it's configurable.
like image 145
Oriol Avatar answered Oct 24 '22 07:10

Oriol