为什么这个可配置的属性不可删除?
Why is this configurable property not deletable?
可配置的属性似乎是可删除的:
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
运算符定义如下:
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.
所以使用delete
的结果取决于[[Delete]]。现在让我们看看 [[Delete]] 做了什么:
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.
因此,如果属性是可配置的,它应该是可删除的。
但是等等,也许 Object.getOwnPropertyDescritor
是一个巨魔并说 属性 是可配置的,但 [[Configurable]] 是 false。让我们看看:
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).
所以它也像[[Delete]]一样使用了[[GetOwnProperty]]。也许巨魔是 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.
所以不,它也不是巨魔。 属性 描述符的 configurable
属性 设置为 [[Configurable]] 值。
那么,一个可配置的属性怎么可能不能被删除呢?
实际上,可配置属性是可删除的。
但是有一个大问题:那只适用于native objects, but not to host objects。
如 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.
对于那些,[[GetOwnProperty]] 必须表现不同:
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.
在您的示例中,form.elements
is a HTMLFormControlsCollection
实例由 HTML 规范定义,因此它是一个宿主对象。
因此,情况是
- 它有一个自定义 [[GetOwnProperty]],表示 属性
'0'
是可配置的,因为它的值可能会改变。
- 它还有一个自定义 [[Delete]],它不会删除 属性,即使 [[GetOwnProperty]] 说它是可配置的。
可配置的属性似乎是可删除的:
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
运算符定义如下:
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.
所以使用delete
的结果取决于[[Delete]]。现在让我们看看 [[Delete]] 做了什么:
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.
因此,如果属性是可配置的,它应该是可删除的。
但是等等,也许 Object.getOwnPropertyDescritor
是一个巨魔并说 属性 是可配置的,但 [[Configurable]] 是 false。让我们看看:
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).
所以它也像[[Delete]]一样使用了[[GetOwnProperty]]。也许巨魔是 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.
所以不,它也不是巨魔。 属性 描述符的 configurable
属性 设置为 [[Configurable]] 值。
那么,一个可配置的属性怎么可能不能被删除呢?
实际上,可配置属性是可删除的。
但是有一个大问题:那只适用于native objects, but not to host objects。
如 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.
对于那些,[[GetOwnProperty]] 必须表现不同:
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.
在您的示例中,form.elements
is a HTMLFormControlsCollection
实例由 HTML 规范定义,因此它是一个宿主对象。
因此,情况是
- 它有一个自定义 [[GetOwnProperty]],表示 属性
'0'
是可配置的,因为它的值可能会改变。 - 它还有一个自定义 [[Delete]],它不会删除 属性,即使 [[GetOwnProperty]] 说它是可配置的。