delete 操作符的行为看起来非常复杂,而且对于它的实际作用存在很多误解。对我来说,似乎重新分配某些东西undefined
会更可靠地完成您的期望。
我从未delete
在非示例代码中实际使用过 Javascript 中的关键字,我想知道它是否对任何东西都特别有用。是否delete
有任何不能通过重新分配到 来实现的目的undefined
?它是否在任何著名的库(例如 jQuery、dojo、backbone 等)中使用过?
delete 操作符的行为看起来非常复杂,而且对于它的实际作用存在很多误解。对我来说,似乎重新分配某些东西undefined
会更可靠地完成您的期望。
我从未delete
在非示例代码中实际使用过 Javascript 中的关键字,我想知道它是否对任何东西都特别有用。是否delete
有任何不能通过重新分配到 来实现的目的undefined
?它是否在任何著名的库(例如 jQuery、dojo、backbone 等)中使用过?
删除是否有任何不能通过重新分配给 undefined 来实现的目的?
是的。如果你想从一个原型或造成财产揭露in
,hasOwnProperty
以及for (...in...)
不记录财产作为现有然后delete
是适当的。
let set = {};
set._x = true;
alert('_x' in set); // true
set._x = undefined;
alert('_x' in set); // true
delete set._x;
alert('_x' in set); // false
编辑:正如 TJ Crowder 解释的那样:
delete
运算符的目的是从对象中完全删除属性,而将属性设置为undefined
仅将属性设置为undefined
。这本身很重要,但在使用继承时也很重要,因为如果 O 派生自 P
let P = { prop: 42 };
let O = Object.create(P); // P is O's prototype.
当您检索 时
O.prop
,如果 O 具有具有该名称的属性(即使其值未定义),您将从 O 获取 prop 的值,但如果 O 根本没有该属性,则将从中检索该值P.prop
。
console.log(O.prop); // "42" since O doesn't have its own prop, but P does.
O.prop = undefined;
console.log(O.prop); // "undefined" since O has its own prop.
delete O.prop;
console.log(O.prop); // "42" since the delete "unmasked" P.prop.
正如 Mike Samuel 在他的回答中指出的那样,delete 最常见的用法之一是当您将对象视为将名称与值相关联的“属性包”时。“这个名字现在被映射到某个虚假值”和“这个名字根本没有被映射”在逻辑上是有区别的。“删除”实现了后者。
这一切都很好理解。我想我可以添加一个关于 JScript 1.0 到 5.0 引擎的有趣历史注释。
在 JScript 的那些原始 Microsoft 实现中,我们使用 OLE 自动化样式的 IDispatch 对象来实现 expando 对象。IDispatch 当然是通过将名称与“调度 ID”相关联来工作的,“调度 ID”只是一个整数。要动态调用,首先您要求调度对象为您提供与名称关联的调度 ID,然后您说“现在调用与此 ID 关联的方法,给定这些参数”。
这一切都很好。但是 IDispatch 契约的要求之一是从名称到调度 ID 的映射在对象的整个生命周期内保持稳定。因此,如果有人说“将属性 Foo 添加到此对象”,那么我们可能会决定属性 Foo 与该对象中的调度标识符 0x1234 相关联。从那一刻起,每次向对象询问“Foo”的调度标识符时,它必须返回 0x1234,即使 Foo 被删除并随后再次添加。这允许调用者维护他们自己的名称/dispid 对的快速缓存,而不是每次调用时都必须询问对象。
其实际结果是“删除”不会以任何方式减轻该实现中对象的内存负担!当您删除一个属性(在原始实现中)时,我们必须向对象中添加一点,将调度标识符标记为已删除,但我们必须保留有关名称/ID 配对的所有信息,以防该名称再次出现。向对象添加大量属性然后删除所有属性不会缩小内存中的对象。
JScript 引擎当然从我那个时代开始就被完全重写了(我相信,除了解析器和词法分析器),所以我不知道引擎是否仍然有这个不寻常的怪癖。找出答案会很有趣。
如果你这样做
delete Foo.Bar;
它从对象 Foo 中完全删除了属性 Bar
Foo.Bar = undefined
只是将 Bar 属性设置为 undefined 并且Foo.Bar
仍然存在
其他答案正在解释delete
关键字背后的动机。我想补充一点,截至 2017 年,浏览器在删除属性和将属性设置为未定义时都会释放内存。
考虑这个例子(来源roughSizeOfObject()
):
> var obj = {a:42,b:"b"}; roughSizeOfObject(obj)
26
> obj.a = undefined; roughSizeOfObject(obj)
18
> delete obj.a; roughSizeOfObject(obj)
10
> obj.b = undefined; roughSizeOfObject(obj)
8
> delete obj.b; roughSizeOfObject(obj)
0
该示例来自 Chrome 61(64 位)控制台(请注意,其中的所有字符都在String
内部编码为 16 位无符号整数)。
您可以查看以下链接的答案Can I set variables to undefined or pass undefined as an argument? 这以非常详细的方式解释了差异。
概括:
您当然可以将 undefined 分配给它,但这不会删除变量。只有 delete object.property 操作符才能真正删除东西。
delete 实际上是用于属性而不是变量本身。浏览器会让你直接删除变量,但这不是一个好主意,并且在 ECMAScript Fifth Edition 的严格模式下不起作用。如果你想释放对某物的引用以便它可以被垃圾收集,通常说 variable=null 会更常见。