All posts

JavaScript / Beware the delete

Posted On 02.18.2022

Unlike C/C++, the delete operator in JavaScript has nothing to do with memory deallocation.

What it actually does is remove a property from its parent object. If there is no more reference to that property, it will be marked as unreachable and will be released when the garbage collector (GC) runs.

In the following example, delete foo.b will mark the string “yolo” as unreachable, and it will eventually be released from the memory:

let foo = {
    a: 12,
    b: "yolo"
};
 
delete foo.b;
 
// foo = { a: 12 }

But in a scenario when two objects shared the same reference, things might not work as you expected.

let boo = { c: true };
 
let foo = {
    a: 12,
    b: boo
};
 
let bar = {
    b: boo
};
 
// foo = { a: 12, b: { c: true } }
// bar = { b: { c: true } }
 
delete foo.b;
 
// foo = { a: 12 }
// bar = { b: { c: true } }

The string boo is shared between foo and bar as the property b, when you delete the reference foo.b, the string boo is still being referenced in bar.b, so it’s still reachable. Hence, nothing will be deleted when the GC runs.


In strict mode, when the delete command is called and the target could not be deleted, a SyntaxError will be thrown. If running in non-strict mode (also known as sloopy mode), a false value will be returned instead.

When a property is created as non-configurable, it cannot be deleted, and a TypeError will be raised instead.

'use strict';
 
var bar = {};
Object.defineProperty(bar, 'hello', { configurable: false });
delete bar.hello; // TypeError
 
 
var foo = {};
Object.defineProperty(foo, 'goodbye', { configurable: true });
delete foo.goodbye; // this works fine

A variable defined with var is either belongs to a scope of the function it’s defined in, or the global scope (if not defined inside any function).

When defined in the global scope, a variable is added as a non-configurable property to the global object. So, it cannot be deleted.

'use strict';
 
// global scope
var hello = "world";
delete globalThis.hello; // Type Error
delete hello; // Syntax Error, see below

Also, in strict mode, if delete is used on a direct reference to a variable, function argument, or a function name, it also throws a Syntax Error:

'use strict';
 
var b = 'xyz';
delete b; // Syntax Error
 
let c = "hello";
delete c; // SyntaxError:
 
const d = 15;
delete d; // SyntaxError
 
function hello(x) {
    delete x; // Syntax Error
}
 
function hello() {}
delete hello; // Syntax Error

Deleting a variable defined with var inside a function is also does not works:

'use strict';
 
function hello() {
    var x = "what's up?";
    delete x; // Syntax Error
}

In non-strict mode, if you define a variable without the var keyword, it will be added to the global object as configurable, hence, we can delete it:

awesome = true;
delete awesome; // true

And if you delete something that does not exist, it also returns true!

delete somethingDoesNotExist; // true!!!

Did you hate the delete yet? Let me make you hate it more.

If you delete an element from an array, it will be gone, but the length of the array is unchanged:

let arr = ['a', 'b', 'c', 'd', 'e', 'f'];
 
<shape of arr> = {
    0: 'a', 1: 'b', 2: 'c',
    3: 'd', 4: 'e', 5: 'f',
    length: 6
}
 
delete arr[3];
 
<shape of arr> = {
    0: 'a', 1: 'b', 2: 'c',
    4: 'e', 5: 'f',
    length: 6
}

This makes perfect sense based on the way delete works, but it will be a lot of pain if someone has to debug array issues because you deleted an element from the array this way.

The right way to remove an element from an array is either to set it to undefined or use Array.prototype.splice:

arr[3] = undefined;
 
<shape of arr> = {
    0: 'a', 1: 'b', 2: 'c',
    3: undefined, 4: 'e', 5: 'f',
    length: 6
}
 
arr.splice(3, 1);
 
<shape of arr> = {
    0: 'a', 1: 'b', 2: 'c',
    3: 'e', 4: 'f',
    length: 5
}