Почему это настраиваемое свойство нельзя удалить?

Настраиваемые свойства кажутся удаляемыми:

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

Но это не работает в следующем случае, по крайней мере, в Firefox и 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

Но это, кажется, противоречит спецификации.

delete Оператор определяется так:

11.4.1 - Оператор удаления

Производство UnaryExpression: delete UnaryExpression оценивается следующим образом:

  • Пусть ref будет результатом вычисления UnaryExpression.
  • [...]
  • Если IsPropertyReference (ref) имеет значение true, то
    • Вернуть результат вызова внутреннего метода [[Delete]] для ToObject ( GetBase (ref)), предоставив в качестве аргументов GetReferencedName (ref) и IsStrictReference (ref).

Итак, результат использования delete зависит от [[Удалить]]. Теперь давайте посмотрим, что делает [[Delete]]:

8.12.7 - [[Удалить]] (P, Бросить)

Когда внутренний метод [[Delete]] для O вызывается с именем свойства P и логическим флагом Throw, предпринимаются следующие шаги:

  • Пусть desc будет результатом вызова внутреннего метода [[GetOwnProperty]] для O с именем свойства P.
  • Если desc не определен, вернуть true.
  • Если значение desc. [[Configurable]] равно true, то
    • Удалите собственное свойство с именем P из O.
    • Верните истину.
  • Иначе, если Throw, тогда выдается исключение TypeError.
  • Вернуть ложь.

Поэтому, если свойство настраивается, его следует удалить.

Но подождите, может быть Object.getOwnPropertyDescritor является троллем и говорит, что свойство можно настраивать, но [[Configurable]] имеет значение false. Посмотрим:

15.2.3.3 - Object.getOwnPropertyDescriptor (O, P)

Когда вызывается функция getOwnPropertyDescriptor, предпринимаются следующие шаги:

  • Если Type (O) не является Object, генерировать исключение TypeError.
  • Пусть имя будет ToString (P).
  • Пусть desc будет результатом вызова внутреннего метода [[GetOwnProperty]] для O с именем аргумента.
  • Вернуть результат вызова FromPropertyDescriptor (desc).

Поэтому он также использует [[GetOwnProperty]], как [[Delete]]. Может быть, тролль это FromPropertyDescriptor?

8.10.4 FromPropertyDescriptor (Desc)

Когда абстрактная операция FromPropertyDescriptor вызывается с дескриптором свойства Desc, предпринимаются следующие шаги:

  • Если Desc не определен, тогда вернуть undefined.
  • Пусть obj будет результатом создания нового объекта, как будто выражением new Object(), где Object является стандартным встроенным конструктором с таким именем.
  • ...
  • Вызвать внутренний метод [[DefineOwnProperty]] объекта obj с аргументами " configurable ", Дескриптор свойства {[[Value]]: Desc. [[Configurable]], [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true } и false.
  • Вернуть объект

Так что нет, это тоже не тролль. configurable свойство дескриптора свойства устанавливается равным значению [[Configurable]].

Как тогда получается, что настраиваемое свойство не может быть удалено?

1 ответ

Решение

По сути, настраиваемые свойства можно удалить.

Но есть большая проблема: это относится только к нативным объектам, но не к хост-объектам.

Как объяснено в 8.6.2 - Внутренние свойства и методы объекта,

Хост-объекты могут поддерживать эти внутренние свойства с любым поведением, зависящим от реализации, если оно согласуется с конкретными ограничениями хост-объекта, указанными в этом документе.

Для них [[GetOwnProperty]] должен вести себя по-другому:

Если свойство описывается как свойство данных и может возвращать различные значения с течением времени, то один или оба атрибута [[Writable]] и [[Configurable]] должны быть истинными, даже если никакой механизм для изменения значения не предоставляется через другие внутренние методы.

В вашем примере form.elements это HTMLFormControlsCollection Экземпляр определяется спецификацией HTML, поэтому это хост-объект.

Таким образом, ситуация

  • У него есть пользовательский [[GetOwnProperty]], который говорит, что свойство '0' настраивается, потому что его значение может измениться.
  • У него также есть пользовательский [[Delete]], который не удаляет свойство, даже если [[GetOwnProperty]] говорит, что оно настраивается.
Другие вопросы по тегам