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"
};

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);

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:

  • 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.
  • 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.


    var myJSONObject = {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};
        
    delete myJSONObject.regex;
    
    console.log ( myJSONObject.regex); // logs: undefined
    链接地址: http://www.djcxy.com/p/27222.html

    上一篇: 如何取消设置JavaScript变量?

    下一篇: 我如何从JavaScript对象中移除一个属性?