Почему это настраиваемое свойство нельзя удалить?
Настраиваемые свойства кажутся удаляемыми:
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
Оператор определяется так:
Производство 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]] говорит, что оно настраивается.