删除不存在的字段的子字段

Ion*_*zău 10 javascript c++ node.js

我刚观察到以下奇怪的行为:

删除未定义的变量

> delete a
true
> delete a[0]
ReferenceError: a is not defined
> delete a.something
ReferenceError: a is not defined
> delete a.something[0]
ReferenceError: a is not defined
Run Code Online (Sandbox Code Playgroud)

删除不存在的字段的子字段

> a = {}
{}
> delete a.foo
true
> delete a.bar.something
TypeError: Cannot convert null to object
> a.bar
undefined
Run Code Online (Sandbox Code Playgroud)

我有两个问题:

  • 为什么delete a工作时a没有定义?
  • 为什么删除a.bar.something抛出的错误Cannot convert null to object,而不是Cannot read property 'something' of undefined(因为a.barundefined)?

根据文档delete操作者,将删除该对象的属性.,那么第一个问题的答案a是应该是this对象的属性?

delete a;应用程序中使用时,会出现此错误(并且应该这样做)error: ‘a’ was not declared in this scope.

Zir*_*rak 5

答案分为两部分.第一个没有描述,但回答了问题,而后者则涉及规范的细节.

TL;博士

  1. 第一行有效,因为在非严格模式下,尝试删除变量才有效.
  2. 第一部分中的其余示例不起作用,因为a未定义
  3. delete a.foo 因为没有理由不应该这样做
  4. delete a.bar.something抛出因为它a.bar在尝试访问之前首先尝试变成对象a.bar.something.

而现在,完全不同的东西

首先,让我们清楚地说明,代码的两个部分在概念上是不同的,因为第一部分讨论了未声明的变量.

我们将看看如何delete指定相当多.

让我们从更容易理解的部分开始:

> delete a[0]
ReferenceError: a is not defined
> delete a.something
ReferenceError: a is not defined
> delete a.something[0]
ReferenceError: a is not defined
Run Code Online (Sandbox Code Playgroud)

所有这些行都试图做一些事情a,一个未声明的变量.因此,你得到一个ReferenceError.到现在为止还挺好.

> delete a
true
Run Code Online (Sandbox Code Playgroud)

这进入了delete声明的第3个条款:a是一个"未解决的引用",这是一种说"它没有被声明"的奇特方式.Spec说true在这种情况下简单地返回.

> a = {}
{}
> delete a.foo
true
Run Code Online (Sandbox Code Playgroud)

这个直观,如你所料(可能),但无论如何让我们深入研究它.delete obj.property进入第4条:

返回[[Delete]]ToObject(GetBase(ref))提供时调用内部方法的结果GetReferencedName(ref)IsStrictReference(ref)作为参数.

Welp那是一件很无趣的事情.让我们忽略[[Delete]]零件之后的所有内容,然后看一下如何[[Delete]]指定.如果我用js写它,它就是这样的:

function Delete (obj, prop) {
    var desc = Object.getOwnPropertyDescriptor(obj, prop);

    if (!desc) {
        return true;
    }

    if (desc.configurable) {
        desc.magicallyRemove(prop);
        return true;
    }

    throw new TypeError('trying to delete a non-configurable property, eh!?');
}
Run Code Online (Sandbox Code Playgroud)

在示例中,a没有名为的属性foo,因此没有什么特别的事情发生.

现在它变得有趣:

> delete a.bar.something
TypeError: Cannot convert null to object
Run Code Online (Sandbox Code Playgroud)

这是因为我们之前忽略了一些无趣的事情:

返回[[Delete]]ToObject(GetBase(ref))[...] 上调用内部方法的结果

我突出显示了与此特定代码段相关的部分.在我们尝试delete任何事情之前,规范告诉我们打电话ToObject(GetBase(ref)),在哪里ref = a.bar.something.那我们就这样做吧!

  • GetBase(a.bar.something) === a.bar
  • ToObject(a.bar)=== ToObject(undefined)哪一个抛出一个TypeError

这解释了最终的行为.

最后的注意事项:您显示的错误消息具有误导性,因为它表示它试图转换null为一个对象,但它没有尝试转换为一个对象undefined.最新的chrome和firefox抛出更准确的一个,但我认为v8最近才修复了错误信息,所以升级到节点v11可能会显示正确的版本.