为什么此可配置属性不可删除

Why is this configurable property not deletable?

本文关键字:删除 属性 配置 为什么      更新时间:2023-09-26
可配置

属性似乎是可删除的:

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 - 删除运算符

生产 UnaryExpressiondelete UnaryExpression 是 评估如下:

  • ref 成为评估 UnaryExpression 的结果。
  • [...]
  • 如果 IsPropertyReference(ref) 为,则
    • 返回在 ToObject(GetBase(ref)) 上调用 [[Delete]] 内部方法的结果,该方法提供 GetReferencedName(ref) 和 IsStrictReference(ref) 作为 参数。

因此,使用 delete 的结果取决于 [[删除]]。现在让我们看看 [[删除]] 的作用:

8.12.7 - [[删除]] (P, 投掷)

当使用属性调用 O 的 [[Delete]] 内部方法时 名称 P 和布尔标志抛出,执行以下步骤:

  • desc 是调用属性名称为 PO 的 [[GetOwnProperty]] 内部方法的结果。
  • 如果未定义desc ,则返回 true
  • 如果描述。[[可配置]] 为真,则
    • O 中删除名为 P 的自有属性。
    • 返回 true
  • 否则,如果抛出
  • ,则抛出TypeError 异常。
  • 返回

因此,如果属性是可配置的,则它应该是可删除的。

但是等等,也许Object.getOwnPropertyDescritor是一个巨魔,说一个属性是可配置的,但[[可配置]]是的。我看看:

15.2.3.3 - Object.getOwnPropertyDescriptor ( O, P )

当调用 getOwnPropertyDescriptor 函数时, 将采取以下步骤:

  • 如果 Type(O) 不是 Object 则引发 TypeError 异常。
  • name 为 ToString(P)。
  • desc 是使用参数名称调用 O 的 [[GetOwnProperty]] 内部方法的结果。
  • 返回调用 FromPropertyDescriptor(desc) 的结果。

所以它也使用[[GetOwnProperty]],如[[Delete]]。也许巨魔是FromPropertyDescriptor?

8.10.4 FromPropertyDescriptor ( desc )

当调用抽象操作 FromPropertyDescriptor 时 属性描述符 Desc,将执行以下步骤:

  • 如果 Desc 未定义,则返回未定义
  • obj 是创建新对象的结果,就像通过表达式 new Object() 一样,其中 Object 是标准的内置 具有该名称的构造函数。
  • 调用 obj 的 [[DefineOwnProperty]] 内部方法,参数 "configurable",属性描述符 {[[Value]]: 德克。[[可配置]]、[[可写]]:真、[[可枚举]]:真、[[可配置]]:}和
  • 返回对象

所以不,它也不是巨魔。属性描述符的 configurable 属性设置为 [[可配置]] 值。

那么,为什么不能删除可配置属性呢?

实际上,可配置的属性是可删除的。

但是有一个大问题:这仅适用于本机对象,而不适用于主机对象。

如 8.6.2 - 对象内部属性和方法中所述,

主机对象可能支持这些内部属性与任何 依赖于实现的行为,只要它符合 本文档中所述的特定主机对象限制。

对于这些,[[GetOwnProperty]]的行为必须不同:

如果属性被描述为数据属性,并且它可能会返回 随时间推移的不同值,然后是 [[可写]] 中的一个或两个 和 [[可配置]] 属性必须为 true,即使没有机制 更改值通过其他内部方法公开。

在您的示例中,form.elements是由 HTML 规范定义的HTMLFormControlsCollection实例,因此它是一个主机对象。

因此,情况是

  • 它有一个自定义的[[GetOwnProperty]],它说属性'0'是可配置的,因为它的值可能会改变。
  • 它还有一个自定义的[[删除]],即使[[GetOwnProperty]]说它是可配置的,也不会删除该属性。