How do I remove a property from a JavaScript object?

How do I remove a property from a JavaScript object?

Say I create an object as follows:
var myObject = {
“ircEvent”: “PRIVMSG”,
“method”: “newURI”,
“regex”: “^http://.*”
};

What is the best way to remove the property regex to end up with new myObject as follows?
var myObject = {
“ircEvent”: “PRIVMSG”,
“method”: “newURI”
};

Solutions/Answers:

Solution 1:

Like this:

delete myObject.regex;
// or,
delete myObject['regex'];
// or,
var prop = "regex";
delete myObject[prop];

Demo

var myObject = {
    "ircEvent": "PRIVMSG",
    "method": "newURI",
    "regex": "^http://.*"
};
delete myObject.regex;

console.log(myObject);

For anyone interested in reading more about it, Stack Overflow user kangax has written an incredibly in-depth blog post about the delete statement on their blog, Understanding delete. It is highly recommended.

Solution 2:

Operator delete is unexpectedly slow!

Look at the benchmark.

Delete is the only true way to remove object’s properties without any leftovers, but it works ~ 100 times slower,
compared to its “alternative”, setting object[key] = undefined.

This alternative is not the correct answer to this question! But, if you use it with care, you can dramatically speed up some algorithms. If you are using delete in loops and you have problems with performance, read the verbose explanation.

When should one use delete and when set value to undefined ?

An object may be seen as a set of key-value pairs. What I call a ‘value’ is a primitive or a reference to other object, connected to that ‘key’.

Use delete, when you are passing the result object to the code on which you don’t have control (or when you are not sure about your team or yourself).

It deletes the key from the hashmap.

 var obj = {
     field: 1     
 };
 delete obj.field;

Use setting to undefined, when you care about performance. It can give a serious boost to your code.

The key remains on its place in the hashmap, only the value is replaced with undefined. Understand, that for..in loop will still iterate over that key.

 var obj = {
     field: 1     
 };
 obj.field = undefined;

Using this method, not all ways of determining property existence will work as expected.

However, this code:

object.field === undefined

will behave equivalently for both methods.

Tests

To summarize, differences are all about ways of determining the property existence, and about for..in loop.

 console.log('* -> "Takes prototype inheritance into consideration, that means it lookups all over prototype chain too."');

 console.log(obj.field === undefined, 'obj.field === undefined', 'You get "undefined" value when querying for "field" in object-hashmap. *');

 console.log(obj["field"] === undefined, 'obj["field"] === undefined', 'Just another way to query (equivalent). *');

 console.log(typeof obj.field === "undefined", 'typeof obj.field === "undefined"', 'Get the value attached to "field" key, and check it\'s type is "undefined". *');

 console.log("field" in obj, '"field" in obj', 'This statement returns true if "field" key exists in the hashmap. False otherwise. *');

 console.log(obj.hasOwnProperty("field"), 'obj.hasOwnProperty("field")', 'This statement returns true if \'field\' key exists in the hashmap. The ONLY way NOT to lookup for property in the prototype chain!');
 //Object.keys().indexOf() is an overkill that runs much slower :)

 var counter = 0,
     key;
 for (key in obj) {
     counter++;
 }
 console.assert(counter === 0, 'counter === 0', '"field" is not iterated using "for .. in" loop. *');

Beware Of Memory Leaks!

While using obj[prop] = undefined is faster than doing delete obj[prop], another important consideration is that obj[prop] = undefined may not always be appropriate. delete obj[prop] removes prop from obj and erases it from memory whereas obj[prop] = undefined simply sets the value of prop to undefined which leaves prop still in memory. Therefore, in circumstances where there are many keys being created and deleted, using obj[prop] = undefined can force expensive memory reconciliation (causing the page to freeze up) and potentially an out-of-memory error. Examine the following code.

"use strict";
var theNodeList=[], i, current, numberOfNodes=65536, body=document.body, nodeRecords=[];
for (i = 0; i !== numberOfNodes; i++) {
    nodeRecords[i] = [];
    current = theNodeList[i] = document.createElement("div");
    current.textContent = i;
    document.body.appendChild( current );
}
var lastTime = -1;
requestAnimationFrame(function recordUpdates(){
    var currentTime = Math.round( performance.now()*1000 )
    for (i = 0; i !== numberOfNodes; i++) {
        if (lastTime !== -1) {
            // the previously collected data is no longer in use
            /*************************************************/
            /****/ nodeRecords[i][lastTime] = undefined; /****/
            /*************************************************/
        }
        nodeRecords[i][currentTime] = theNodeList[i].outerHTML;
    }
    lastTime = currentTime;
    requestAnimationFrame( recordUpdates );
});

In the code above, simply doing nodeRecords[i][lastTime] = undefined; will cause a massive memory leak because each animation frame. Each frame, all 65536 DOM elements will take up another 65536 individual slots, but the previous 65536 slots will only be set to undefined which leaves them hanging in the memory. Go ahead, try to run the above code in the console and see for yourself. After forcing an out-of-memory error, attempt to run it again except with the following version of the code that uses the delete operator instead.

"use strict";
var theNodeList=[], i, current, numberOfNodes=65536, body=document.body, nodeRecords=[];
for (i = 0; i !== numberOfNodes; i++) {
    nodeRecords[i] = [];
    current = theNodeList[i] = document.createElement("div");
    current.textContent = i;
    document.body.appendChild( current );
}
var lastTime = -1;
requestAnimationFrame(function recordUpdates(){
    var currentTime = Math.round( performance.now()*1000 )
    for (i = 0; i !== numberOfNodes; i++) {
        if (lastTime !== -1) {
            // the previously collected data is no longer in use
            /********************************************/
            /****/ delete nodeRecords[i][lastTime]; /****/
            /********************************************/
        }
        nodeRecords[i][currentTime] = theNodeList[i].outerHTML;
    }
    lastTime = currentTime;
    requestAnimationFrame( recordUpdates );
});

As seen in the above code snippet, there are some rare appropriate use cases for the delete operator. However, do not worry about this problem too much. This will only become a problem with long-lifespan objects that get new keys constantly added to them. In any other case (which is almost every case in real-world programming), it is most appropriate to use obj[prop] = undefined. The main purpose of this section is just to bring this to your attention so that in the rare chance that this does become a problem in your code, then you can more easily understand the problem and thus not have to waste hours dissecting your code to locate and understand this problem.

Do Not Always Set To undefined

One aspect of Javascript that is important to consider is polymorphism. Polymorphism is when assigning the same variable/slot-in-an-object different types as seen below.

var foo = "str";
foo = 100;          // variable foo is now labeled polymorphic by the browser
var bar = ["Some", "example"];
bar[2] = "text";    // bar is a monomorphic array here because all its entries have the
                    // same type: string primitive
bar[1] = undefined; // bar is now a polymorphic array

However, there are two major unfixable problems with polymorphic arrays:

  1. They are slow & memory inefficient. When accessing a specific index, instead of just getting the global type for the array, the browser instead has to get the type on a per-index basis whereby each index stores the additional metadata of its type.
  2. Once polymorphic, always polymorphic. When an array is made polymorphic, the polymorphism cannot be undone in Webkit browsers. So, even if you restore a polymorphic array to being non-polymorphic, it will still be stored by the browser as a polymorphic array.

One may liken polymorphism to a drug addiction. At first glance, it seems awesomely lucrative: nice pretty fluffy code. Then, the coder introduces their array to the drug of polymorphism. Instantly, the polymorphic array becomes less efficient, and it can never become as efficient as it was before since it is drugged. To correlate such circumstance to real life, someone on cocaine might not even be capable of operating a simple door handle, much less be able to calculate digits of PI. Likewise, an array on the drug of polymorphism cannot ever be as efficient as a monomorphic array.

But, how does a drug trip analogy relate to the delete operation? The answer inheres the last line of code in the snippet above. Thus let it be reexamined, this time with a twist.

var bar = ["Some", "example"];
bar[2] = "text";    // bar is not a polymorphic array here because all its entries have the
                    // same type: string primitive
bar[1] = "";        // bar is still a monomorphic array
bar[1] = undefined; // bar is now a polymorphic array

Observe. bar[1] = "" does not coerce polymorphism whereas bar[1] = undefined does. Therefore, one should always, whenever possible use the corresponding type for their objects so as to not accidentally cause polymorphism. One such person may use the following list as a general reference to get them going. However, please do not explicitly use the below ideas. Instead, use whatever works well for your code.

  • When using an array/variable typed to the boolean primitive, use either false or undefined as the empty value. While avoiding unnecessary polymorphism is good, rewriting all your code to explicitly forbid it will likely actually result in a decrease in performance. Use common judgement!
  • When using an array/variable typed to the number primitive, use 0 as the empty value. Note that internally, there are two types of numbers: fast integers (2147483647 to -2147483648 inclusive) and slow floating point doubles (anything other than that including NaN and Infinity). When an integer is demoted to a double, it cannot be promoted back to an integer.
  • When using an array/variable typed to the string primitive, use "" as the empty value.
  • When using a Symbol, wait, why are you using a Symbol?!?! Symbols are bad juju for performance. Everything programmed to use Symbols can be reprogrammed to not use Symbols, resulting in a faster code without Symbols. Symbols are really just super inefficient meta-sugar.
  • When using anything else, use null.

However, be mindful! Do not suddenly start doing this with all your preexisting code now as it would likely break such preexisting code and/or introduce strange bugs. Rather, such an efficient practice needs to be implemented from the start, and when converting preexisting code, it is recommended that you double, triple, quadruple check all the lines relating to that as trying to upgrade old code to this new practice can be as risky as it is rewarding.

Solution 3:

var myObject = {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};
    
delete myObject.regex;

console.log ( myObject.regex); // logs: undefined

This works in Firefox and Internet Explorer, and I think it works in all others.

Solution 4:

Update 2018-07-21: For a long time, I have felt embarrassed about this answer, so I think it’s time that I touch it up a little bit. Just a little commentary, clarification, and formatting to help expedite the reading of the needlessly long and convoluted parts of this answer.


THE SHORT VERSION

The actual answer to the question

As others have said, you can use delete.

obj // {"foo": "bar"}
delete obj["foo"]
obj // {}
obj["foo"] // undefined

Array equivalent

Don’t delete from an array. Use Array.prototype.splice instead.

arr // [1,2,3,4,5]
arr.splice(3,1); // 4
arr // [1,2,3,5]

THE LONG VERSION

JavaScript is an OOP Language, so everything is an object, including arrays. Thus, I feel it necessary to point out a particular caveat.

In arrays, unlike plain old objects, using delete leaves behind garbage in the form of null, creating a “hole” in the array.

var array = [1, 2, 3, 4];
delete array[2];
/* Expected result --> [1, 2, 4]
 * Actual result   --> [1, 2, null, 4]
 */

As you can see, delete doesn’t always work as one might expect. The value is overwritten, but the memory is not reallocated. That is to say, array[4] isn’t relocated to array[3]. Which is in contrast to Array.prototype.unshift, which inserts an element at the beginning of the array and shifts everything up (array[0] becomes array[1], etc.)

Honestly, aside from setting to null rather than undefined–which is legitimately weird–this behavior shouldn’t be surprising, since delete is a unary operator, like typeof, that is hard-boiled into the language and is not supposed to care about the type of object it’s being used on, whereas Array is a subclass of Object with methods specifically designed for working with arrays. So there’s no good reason for delete to have a special case cooked in for re-shifting the array, as that would just slow things down with unnecessary work. In retrospect, my expectations were unrealistic.

Of course, it did surprise me. Because I wrote this to justify my crusade against “null garbage”:

Ignoring the dangers and problems inherent in null, and the space wasted, this can be problematic if the array needs to be precise.

Which is a terrible justification for getting rid of the nulls–null is only dangerous if used improperly, and it has nothing to do with “precision”. The real reason you shouldn’t delete from an array is that leaving garbage-filled and messy data structures around is sloppy and bug-prone.

What follows is a contrived scenario that gets pretty long-winded, so you can skip to the section, The Solution, if you want. The only reason I leave this section it is that I think some people probably think it’s funny, and I don’t want to be “that guy” who posts a “funny” answer and then deletes all the “funny” from it later on.

…It’s stupid, I know.

The contrived and long-winded PDP-11 scenario

For example, say you are creating a webapp that uses JSON-serialization to store an array used for ‘tabs’ in a string (in this case, localStorage). Let’s also say that the code uses the numerical indices of the array’s members to “title” them when drawing to the screen. Why are you doing this rather than just storing the “title” as well? Because… reasons.

Okay, let’s just say that you’re trying to save memory at the request of this one user who runs a PDP-11 minicomputer from the 1960’s running UNIX and wrote his own Elinks-based, JavaScript-compliant, line-printer-friendly browser because X11 is out of the question.

Increasingly stupid edge-case scenario aside, using delete on said array will result in null polluting the array, and probably causing bugs in the app later on. And if you check for null, it would straight up skip the numbers resulting in the tabs being rendered like [1] [2] [4] [5] ....

if (array[index] == null)
    continue;
else
    title = (index + 1).toString();
/* 0 -> "1"
 * 1 -> "2"
 * 2 -> (nothing)
 * 3 -> "4"
 */

Yeah, that’s definitely not what you wanted.

Now, you could keep a second iterator, like j, to increment only when valid values are read from the array. But that wouldn’t exactly solve the null issue, and you still have to please that troll PDP-11 user. Alas, his computer just doesn’t have enough memory to hold that last integer (don’t ask how he manages to handle a variable-width array…).

So, he sends you an email in anger:

Hey, your webapp broke my browser! I checked my localStorage database after your stupid code made my browser segfault, and this is what I found:

>"tabs:['Hello World', 'foo bar baz', null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, ... ]"

After clearing my precious data, it segfaulted again, and I did a backtrace, and what do I find? WHAT DO I FIND!? YOU USE TOO MANY VARIABLES!

>var i = index;
>var j = 1;

Grr, I am angry now.
-Troll Davidson

About now, you’re at your wit’s end. This guy has been complaining non-stop about your app, and you want to tell him to shut up and go get a better computer.

The Solution: Array.prototype.splice

Luckily, arrays do have a specialized method for deleting indices and reallocating memory: Array.prototype.splice(). You could write something like this:

Array.prototype.remove = function(index){
  this.splice(index,1);
}
...
array = [1, 2, 3, 4];
array.remove(2);
// Result -> [1, 2, 4]

And just like that, you’ve pleased Mr. PDP-11. Hooray! (I’d still tell him off, though…)

Array.prototype.splice vs Array.prototype.slice

I feel it’s important to point out the difference between these two similarly-named functions, as they are both very useful.

Array.prototype.splice(start, n)

.splice() mutates the array, and returns the removed indices. The array is sliced starting from the index, start, and n elements are sliced out. If n is unspecified, the entire array after start is sliced out (n = array.length - start).

let a = [5,4,3,2,1];
let chunk = a.splice(2,2);

// a     [5,4,3,2,1]
// start  0 1 2 - -
// n      - - 1 2 -

chunk; // [3,2]
a;     // [5,4,1]

Array.prototype.slice(start, end)

.slice() is non-destructive and returns a new array containing the indicated indices from start to end. If end is left unspecified, the behavior is the same as .splice() (end = array.length). The behavior is a bit tricky since, for some reason, end indexes from 1 instead of 0. I don’t know why it does this, but that’s how it is. Also, if end <= start, the result is an empty array.

let a = [5,4,3,2,1];
let chunks = [
    a.slice(2,0),
    a.slice(2,2),
    a.slice(2,3),
    a.slice(2,5) ];

// a             [5,4,3,2,1]
// start          0 1 2 - -
// end, for...    - - - - -
//   chunks[0]  0 - - - - -   
//   chunks[1]    1 2 - - -
//   chunks[2]    1 2 3 - -
//   chunks[3]    1 2 3 4 5

chunks; // [ [], [], [3], [3,2,1] ]
a;      // [5,4,3,2,1]

That actually isn’t what’s happening, but it’s easier to think of that way. According to MDN, here’s what’s actually happening:

// a             [5,4,3,2,1]
// start          0 1 2 - - -
// end, for...    - - - - - -
//   chunks[0]    0 - - - - -
//   chunks[1]    0 1 2 - - -
//   chunks[2]    0 1(2)3 - -
//   chunks[3]    0 1(2 3 4)5

The index specified by end is simply excluded from the slice. The parenthesized indices indicate what gets sliced. Either way, the behavior is not intuitive and it’s bound to cause its fair share of off-by-one errors, so you might find it useful to make a wrapper function to more closely emulate the behavior of .splice():

function ez_slice(array, start = 0, n = null){
    if(!Array.isArray(array) || !is_number(start))
        return null;

    if(is_number(n))
        return array.slice(start, start + n);

    if(n === null)
        return array.slice(start);

    return null;
}

ez_slice([5,4,3,2,1], 2, 1) // [3]
ez_slice([5,4,3,2,1], 2)    // [3,2,1]

/* Fun fact: isNaN is unreliable.
 * [NaN, [], {}, 0, 1, Infinity, undefined, null, "Hi"].filter(isNaN)
 * [NaN, {}, undefined, "Hi"]
 *
 * What we want is...
 *
 * [NaN, [], {}, 0, 1, Infinity, undefined, null, "Hi"].filter(is_nan)
 * [NaN]
 */
function is_nan(num){
    return typeof num === "number"
        && num !== num;
}

function is_number(num){
    return !is_nan(num)
        && typeof num === "number"
        && isFinite(num);
}

Note that the wrapper function is designed to be very strict about types, and will return null if anything is off. That includes putting in a string like "3". It is left up to the programmer to be diligent about his types. This is to encourage good programming practice.

Update regarding is_array()

This is in regard to this (now-removed) snippet:

function is_array(array){
    return array !== null
        && typeof array === "object"
        && typeof array.length !== "undefined"
        && array.__proto__ === Array.prototype;
}

So as it turns out, there actually IS a built-in way to tell if an array is truly an array, and that is Array.isArray(), introduced in ECMAScript 5 (December 2009). I found this while looking to see if there was a question asking about telling arrays from objects, to see if there was either a better solution than mine, or to add mine if there were none. So, if you’re using a version of JavaScript that is earlier than ECMA 5, there’s your polyfill. However, I strongly recommend against using my is_array() function, as continuing to support old versions of JavaScript means continuing to support the old browsers that implement them, which means encouraging the use of insecure software and putting users at risk for malware. So please, use Array.isArray(). Use let and const. Use the new features that get added to the language. Don’t use vendor prefixes. Delete that IE polyfill crap from your website. Delete that XHTML <!CDATA[[... crap, too–we moved to HTML5 back in 2014. The sooner everybody withdraws support for those old/esoteric browsers, the sooner the browser vendors will actually follow the web standard and embrace the new technology, and the sooner we can move on to a more secure web.

Solution 5:

Old question, modern answer. Using object destructuring, an ECMAScript 6 feature, it’s as simple as:

const { a, ...rest } = { a: 1, b: 2, c: 3 };

Or with the questions sample:

const myObject = {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};
const { regex, ...newObject } = myObject;
console.log(newObject);

You can see it in action in the Babel try-out editor.


Edit:

To reassign to the same variable, use a let:

let myObject = {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};
({ regex, ...myObject } = myObject);
console.log(myObject);

Solution 6:

Another alternative is to use the Underscore.js library.

Note that _.pick() and _.omit() both return a copy of the object and don’t directly modify the original object. Assigning the result to the original object should do the trick (not shown).

Reference: link _.pick(object, *keys)

Return a copy of the object, filtered to only have values for the
whitelisted keys (or array of valid keys).

var myJSONObject = 
{"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};

_.pick(myJSONObject, "ircEvent", "method");
=> {"ircEvent": "PRIVMSG", "method": "newURI"};

Reference: link _.omit(object, *keys)

Return a copy of the object, filtered to omit the
blacklisted keys (or array of keys).

var myJSONObject = 
{"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};

_.omit(myJSONObject, "regex");
=> {"ircEvent": "PRIVMSG", "method": "newURI"};

For arrays, _.filter() and _.reject() can be used in a similar manner.