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

时间:2014-11-14 10:15:40

标签: 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

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

> 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

2 个答案:

答案 0 :(得分:5)

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

TL;博士

  1. 第一行有效,因为在非严格模式下,尝试删除变量才有效。
  2. 第一部分中的其余示例不起作用,因为未定义a
  3. delete a.foo有效,因为没有理由不应该
  4. delete a.bar.something因为在尝试访问a.bar之前首先尝试将a.bar.something转换为对象而抛出。
  5. 现在有一些完全不同的东西

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

    我们会相当关注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条:

      

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

    Welp这是一件很无趣的事情。让我们忽略[[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
    

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

      

    返回在 [[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可能会显示正确的版本。

答案 1 :(得分:0)

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

<强> 1。为什么在未定义时删除作品?

  

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

     

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

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

var a;
delete a;

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

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

<强> 2。为什么删除a.bar.something会抛出错误无法将null转换为对象而不能读取未定义的属性“某事”?

请看这些例子:

<强> 的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

如您所见,在测试a.b时,两者都会将typeof作为未定义的值进行管理。但是在删除时,chrome表示它可能是undefinednull,而NodeJS认为这是null值。

NodeJS错误是否可能被错误格式化?