What is the purpose of the delete operator in Javascript?
Solution 1:
Does delete have any purpose that cannot be acheived by reassignment to 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.
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 T.J. Crowder explains:
The purpose of the
delete
operator is to completely remove a property from an object, whereas setting a property toundefined
just sets the property toundefined
.This matters in its own right, but it also matters when you're using inheritance, because if O derives from 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 fromP.prop
instead.
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.
Solution 2:
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. 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.
In those original Microsoft implementations of JScript we used OLE Automation-style IDispatch objects to implement expando objects. IDispatch of course works by associating a name with a "dispatch id", which is simply an integer. 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".
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. 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. 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. 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.
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. 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. It would be interesting to find out.
Solution 3:
If you do
delete Foo.Bar;
it deletes the property Bar from object Foo entirely
Foo.Bar = undefined
merely sets Bar property to undefined and Foo.Bar
still exists
Solution 4:
The other answers are explaining the motivation behind the delete
keyword. 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.
Consider this example (source of 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).