删除不存在的字段的子字段
Deleting a subfield of a field that doesn't exist
我刚刚观察到以下奇怪的行为:
删除未定义的变量
> 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.bar
undefined
)?
根据文档 delete
运算符从对象中删除属性,因此第一个问题的答案是a
应该是this
对象的属性?
在 c++ 应用程序中使用 delete a;
时,此错误出现(并且应该出现)error: ‘a’ was not declared in this scope
。
答案一分为二。前者没有描述太多,但回答了问题,而后者则进入了规范的细节。
博士
- 第一行有效,因为在非严格模式下,尝试删除变量只是有效的。
- 第一部分中的其余示例不起作用,因为未定义
a
-
delete a.foo
有效,因为没有理由不应该这样做 -
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
所有这些行都试图用a
做一些事情,一个没有声明的变量。因此,你会得到一个ReferenceError
.目前为止,一切都好。
> delete a
true
这就进入了delete
语句的第3条:a
是一个"未解决的引用",这是一种说"它没有声明"的奇特方式。Spec说在这种情况下简单地返回true
。
> a = {}
{}
> delete a.foo
true
正如您所期望的那样,这个很直观(可能),但无论如何让我们深入研究它。 delete obj.property
进入第四条:
返回在提供
GetReferencedName(ref)
和IsStrictReference(ref)
作为参数ToObject(GetBase(ref))
调用[[Delete]]
内部方法的结果。
呜,这是一大堆无趣的东西。让我们忽略[[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!?');
}
在示例中,a
没有名为 foo
的属性,因此不会发生任何特殊情况。
现在它变得有趣了:
> delete a.bar.something
TypeError: Cannot convert null to object
发生这种情况是由于我们之前忽略的一些无趣的事情:
返回在
ToObject(GetBase(ref))
上调用[[Delete]]
内部方法的结果 [...]
我突出显示了与此特定片段相关的部分。在我们尝试delete
任何东西之前,spec 告诉我们调用 ToObject(GetBase(ref))
,ref = a.bar.something
在哪里。那就这样吧!
-
GetBase
(a.bar.something) === a.bar
-
ToObject
(a.bar)
=== 抛出TypeError
的ToObject(undefined)
这解释了最终的行为。
最后说明:您显示的错误消息具有误导性,因为它说它试图将null
转换为对象,但它没有,因为它试图将undefined
转换为一个对象。最新的chrome和Firefox抛出了一个更准确的版本,但我认为v8最近才修复了错误消息,所以也许升级到节点v11会显示正确的版本。
我正在分享实验和阅读材料,希望这会有所帮助!
1. 为什么要删除未定义的作品?
如果您尝试读取不存在的属性,JavaScript 会返回 "未定义"。这很方便,但如果您不这样做,则可以掩盖错误 小心,所以要注意错别字!
来源:http://www.w3.org/wiki/Objects_in_JavaScript
"Delete"将同时删除值和属性,因此只要 JavaScript 返回 a
的值,delete 的工作方式与此示例相同:
var a;
delete a;
此外,正如您所说a
是this
对象的属性。您可以通过测试此代码来查看以下内容:
> var a = {}
undefined
> a
{}
> this.a
{}
2. 为什么删除 a.bar.something 会抛出错误 无法将 null 转换为对象而不是无法读取未定义的属性"某物"?
请看这些例子:
节点JS:
> 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 错误格式错误?
- 链接器找不到在虚拟类 c++ 中访问的静态字段的符号
- 如何在QByteArray中放置和检索位字段而不会感到痛苦?
- 错误:字段'dateOfBirth'的类型不完整'Poco::Data::Date'
- sizeof 函数如何在带和不带位字段的结构上工作?(填充)
- 如何在不混淆字段的情况下声明复数?
- protobuf,如何在protobuf消息中遍历所有集合字段,我不知道详细信息?(C++)
- 无法访问 Arduino 结构字段。错误"退出状态 1。xxxx 不命名类型"
- uninit_member:非静态类成员字段 m_cJobState.bstatus 未在此构造函数中初始化,也不在其调
- C++ Arduino:向下转换后,子字段不引用原始地址
- 为什么将值分配给一个位字段不给予相同的值
- 在C++实例中,字段不会初始化为其默认值.静态字段怎么样
- 为什么枚举与 Windows 中的位字段不兼容
- 删除不存在的字段的子字段
- 如何检查结构的类型或字段是否存在
- 在c++中正确的对象强制转换,值字段不会改变
- 类字段不能在函数内部访问
- c++中的空字段和不存在的字段
- 为什么本地类中的字段不能是静态的
- 用于检查字段是否存在的Sqlite查询失败
- QODBCResult::exec: 无法执行语句:"[Microsoft][ODBC SQL Server Driver]COUNT 字段不正确或语法错误