【问题标题】:Deleting a subfield of a field that doesn't exist删除不存在的字段的子字段
【发布时间】:2015-01-11 16:53:13
【问题描述】:

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

删除未定义的变量

> 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

【问题讨论】:

    标签: c++ javascript c++ node.js


    【解决方案1】:

    我正在分享实验和读数,希望这会有所帮助!

    1.为什么要删除未定义的作品?

    如果您尝试读取不存在的属性,JavaScript 会返回 “不明确的”。这很方便,但如果你不这样做可以掩盖错误 小心,所以要注意拼写错误!

    来源http://www.w3.org/wiki/Objects_in_JavaScript

    “删除”会同时删除值和属性,因此只要 JavaScript 返回 a 的值,删除的工作方式与此示例相同:

    var a;
    delete a;
    

    此外,正如您所说,athis 对象的属性。你可以通过测试这段代码看到这一点:

    > var a = {}
    undefined
    > a
    {}
    > this.a
    {}
    

    2。为什么删除a.bar.something会抛出错误Cannot convert null to object而不是Cannot read property 'something' of undefined?

    请看这些例子:

    NodeJS:

    > var a = {}
    undefined
    > typeof a.b
    'undefined'
    > typeof a.b.c
    TypeError: Cannot read property 'c' of undefined
        at repl:1:12
        at ......
    > delete a.b.c
    TypeError: Cannot convert null to object
        at repl:1:10
        at ......
    

    Chrome 控制台:

    > var a ={}
    undefined
    > typeof a.b
    "undefined"
    > typeof a.b.c
    Uncaught TypeError: Cannot read property 'c' of undefined VM335:2
    > delete a.b.c
    Uncaught TypeError: Cannot convert undefined or null to object
    

    如您所见,在测试typeof 时,两者都会将a.b 管理为未定义的值。但是删除的时候,chrome说可能是undefined或者null,而NodeJS认为这是null的值。

    会不会是 NodeJS 错误格式错误?

    【讨论】:

      【解决方案2】:

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

      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 语句的第三个子句:a 是一个“未解析的引用”,这是一种说“它没有被声明”的奇特方式。 Spec说在这种情况下简单地返回true

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

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

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

      哎呀,这是一大堆无趣的东西。让我们忽略[[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
      

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

      返回在 ToObject(GetBase(ref)) [...]

      上调用 [[Delete]] 内部方法的结果

      我突出显示了与此特定 sn-p 相关的部分。在我们尝试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 可能会显示正确的版本。

      【讨论】:

        猜你喜欢
        • 2020-11-05
        • 2017-09-14
        • 1970-01-01
        • 2011-10-10
        • 1970-01-01
        • 2016-06-26
        • 1970-01-01
        • 2021-01-22
        • 1970-01-01
        相关资源
        最近更新 更多