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

标签 javascript c++ node.js

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

删除 undefined variable

> 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

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

> a = {}
{}
> delete a.foo
true
> delete a.bar.something
TypeError: Cannot convert null to object
> a.bar
undefined

我有两个问题:

  • 为什么 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.

最佳答案

答案分为两部分。第一个描述不多,但回答了这个问题,而后者则进入了规范的基本细节。

tl;博士

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

现在完全不同了

首先,让我们明确两段代码在概念上是不同的,因为第一段讨论的是一个未声明的变量。

我们将关注 how delete is specified相当多。

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

> 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

所有这些行都试图用 a 做一些事情,这是一个未声明的变量。因此,您会得到一个 ReferenceError。到目前为止一切顺利。

> delete a
true

这进入 delete 语句的第 3 个子句:a 是一个“未解析的引用”,这是说“它没有被声明”的一种奇特方式. Spec 说在这种情况下简单地返回 true

> a = {}
{}
> delete a.foo
true

这很直观,正如您所期望的那样(可能),但无论如何让我们深入研究一下。 delete obj.property 进入第 4 个子句:

Return the result of calling the [[Delete]] internal method on ToObject(GetBase(ref)) providing GetReferencedName(ref) and IsStrictReference(ref) as the arguments.

哎呀,这是一大堆无趣的东西。让我们忽略 [[Delete]] 部分之后的所有内容,只看 how [[Delete]] is specified .如果我用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!?');
}

在示例中,a 没有名为 foo 的属性,因此不会发生任何特殊情况。

现在变得有趣了:

> delete a.bar.something
TypeError: Cannot convert null to object

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

Return the result of calling the [[Delete]] internal method on 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 只是最近才修复了错误消息,所以升级到 node v11 可能会显示正确的版本。

关于javascript - 删除不存在的字段的子字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26927605/

相关文章:

javascript - 什么是可以用来递增字母的方法?

javascript - 如何在 PHP Laravel 中为货币值设置自动数字 jquery?

java - 为 C++ 服务器实现 Java TCP 客户端

c++ - 默认模板参数结果为 "expected type-specifier"

javascript - 我可以将基于 Node 的项目迁移到 Deno 吗?

javascript - 在 win8 应用程序中设置 <video> 元素的样式 (html/js)

c++ - 将 const char 数组初始化为重载函数的参数

node.js - 如何在 Jest afterAll 钩子(Hook)中关闭 Express 服务器

php - Nodejs上传图片到其他服务器API

javascript - knockout : Change observable value