简体   繁体   English

Javascript 中删除运算符的目的是什么?

[英]What is the purpose of the delete operator in Javascript?

The behaviour of the delete operator seems very complicated and there are many misunderstandings about what it actually does . delete 操作符的行为看起来非常复杂,而且对于它的实际作用存在很多误解 To me, it seems that reassigning something to undefined will more reliably do what you would expect.对我来说,似乎将某些东西重新分配给undefined会更可靠地完成您的期望。

I've never seen the delete keyword in Javascript actually used in non-example code and I am wondering if it is particularly useful for anything.我从未见过在非示例代码中实际使用的 Javascript 中的delete关键字,我想知道它是否对任何东西特别有用。 Does delete have any purpose that cannot be acheived by reassignment to undefined ? delete是否有任何不能通过重新分配给undefined来实现的目的? Is it used at all in any of the famous libraries (eg jQuery, dojo, backbone, etc)?它是否在任何著名的库(例如 jQuery、dojo、backbone 等)中使用过?

Does delete have any purpose that cannot be acheived by reassignment to undefined?删除是否有任何不能通过重新分配给 undefined 来实现的目的?

Yes.是的。 If you want to unmask a property from a prototype or cause in , hasOwnProperty , and for (...in...) to not record the property as existing then delete is appropriate.如果您想从原型中取消屏蔽属性或导致inhasOwnPropertyfor (...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

EDIT: As TJ Crowder explains:编辑:正如 TJ Crowder 解释的那样:

The purpose of the delete operator is to completely remove a property from an object, whereas setting a property to undefined just sets the property to undefined . delete运算符的目的是从对象中完全删除一个属性,而将属性设置为undefined只是将属性设置为undefined

This matters in its own right, but it also matters when you're using inheritance, because if O derives from P这本身很重要,但在使用继承时也很重要,因为如果 O 派生自 P

let P = { prop: 42 };
let O = Object.create(P);  // P is O's prototype.

when you retrieve O.prop , you get the value of prop from O if O has a property with that name (even if its value is undefined), but if O doesn't have the property at all, then the value will be retrieved from P.prop instead.当您检索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.

As Mike Samuel points out in his answer, one of the most common usages of delete is when you are treating an object as a "property bag" that associates names with values.正如 Mike Samuel 在他的回答中指出的那样,delete 最常见的用法之一是当您将对象视为将名称与值相关联的“属性包”时。 There is logically a difference between "this name is now mapped to some bogus value" and "this name is not mapped at all". “这个名字现在被映射到某个虚假值”和“这个名字根本没有被映射”在逻辑上是有区别的。 "delete" achieves the latter. “删除”实现了后者。

That's all reasonably well understood.这一切都很好理解。 I thought I might add an interesting historical note regarding the JScript 1.0 through 5.0 engines.我想我可以添加一个关于 JScript 1.0 到 5.0 引擎的有趣历史注释。

In those original Microsoft implementations of JScript we used OLE Automation-style IDispatch objects to implement expando objects.在 JScript 的那些原始 Microsoft 实现中,我们使用 OLE 自动化样式的 IDispatch 对象来实现 expando 对象。 IDispatch of course works by associating a name with a "dispatch id", which is simply an integer. IDispatch 当然是通过将名称与“调度 ID”相关联来工作的,“调度 ID”只是一个整数。 To invoke dynamically, first you ask the dispatch object to give you the dispatch ID associated with a name, and then you say "now invoke the method associated with this ID, given these arguments".要动态调用,首先您要求调度对象为您提供与名称关联的调度 ID,然后您说“现在调用与此 ID 关联的方法,给定这些参数”。

That's all well and good.这一切都很好。 But one of the requirements of the IDispatch contract is that the mapping from name to dispatch ID be stable over the entire lifetime of the object .但是 IDispatch 契约的要求之一是从名称到调度 ID 的映射在对象的整个生命周期内保持稳定 So if someone says "add property Foo to this object", then we might decide that property Foo is associated with dispatch identifier 0x1234 in that object.因此,如果有人说“将属性 Foo 添加到此对象”,那么我们可能会决定属性 Foo 与该对象中的调度标识符 0x1234 相关联。 From that moment on, every time the object is asked for the dispatch identifier of "Foo", it must give back 0x1234, even if Foo is deleted and subsequently added again.从那一刻起,每次向对象询问“Foo”的调度标识符时,它必须返回 0x1234,即使 Foo 被删除并随后再次添加。 This permits a caller to maintain their own fast cache of name/dispid pairs rather than always having to ask the object on every invocation.这允许调用者维护他们自己的名称/dispid 对的快速缓存,而不是每次调用时都必须询问对象。

The practical upshot of that is that "delete" does not in any way lessen the memory burden on the object in that implementation !其实际结果是“删除”不会以任何方式减轻该实现中对象的内存负担 When you delete a property (in the original implementation) we must add a bit to the object marking that dispatch identifier as deleted, but we must retain all the information about the name/id pairing in case that name ever comes back.当您删除一个属性(在原始实现中)时,我们必须向对象中添加一点,将调度标识符标记为已删除,但我们必须保留有关名称/ID 配对的所有信息,以防该名称再次出现。 Adding a huge number of properties to an object and then deleting all of them does not shrink the object in memory.向对象添加大量属性然后删除所有属性不会缩小内存中的对象。

The JScript engine has of course been completely rewritten since my time (except for, I believe, the parser and lexer) so I have no idea if the engine still has this unusual quirk. JScript 引擎当然从我那个时代起就被完全重写了(我相信除了解析器和词法分析器),所以我不知道引擎是否仍然有这个不寻常的怪癖。 It would be interesting to find out.找出答案会很有趣。

If you do如果你这样做

 delete Foo.Bar;

it deletes the property Bar from object Foo entirely它从对象 Foo 中完全删除了属性 Bar

 Foo.Bar = undefined

merely sets Bar property to undefined and Foo.Bar still exists只是将 Bar 属性设置为 undefined 并且Foo.Bar仍然存在

The other answers are explaining the motivation behind the delete keyword.其他答案正在解释delete关键字背后的动机。 I would like to add that as of 2017, browser do deallocate memory both when deleting a property and when setting the property to undefined.我想补充一点,截至 2017 年,浏览器在删除属性和将属性设置为未定义时都会释放内存

Consider this example ( source of roughSizeOfObject() ):考虑这个例子( 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

The example comes from Chrome 61 (64-bit) console (note that all characters in String are internally encoded as 16-bit unsigned integer).该示例来自 Chrome 61(64 位)控制台(请注意, String中的所有字符都在内部编码为 16 位无符号整数)。

You can check the answer of the following link Can I set variables to undefined or pass undefined as an argument?您可以查看以下链接的答案Can I set variables to undefined or pass undefined as an argument? which explains the difference in a very detailed way.这以非常详细的方式解释了差异。

Summary:概括:

You can certainly assign undefined to it, but that won't delete the variable.您当然可以将 undefined 分配给它,但这不会删除变量。 Only the delete object.property operator really removes things.只有 delete object.property 操作符才能真正删除东西。

delete is really meant for properties rather than variables as such. delete 实际上是用于属性而不是变量本身。 Browsers will let you get away with straight delete variable, but it's not a good idea and won't work in ECMAScript Fifth Edition's strict mode.浏览器会让你直接删除变量,但这不是一个好主意,并且在 ECMAScript Fifth Edition 的严格模式下不起作用。 If you want to free up a reference to something so it can be garbage-collected, it would be more usual to say variable= null.如果你想释放对某物的引用以便它可以被垃圾收集,通常说 variable=null 会更常见。

Well, you'd end up with an element in your object that contains the value undefined .好吧,您最终会在对象中得到一个包含值undefined的元素。 The key wouldn't be gone.钥匙不会消失。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM