101

I have this Javascript object.

req.session

In my code I add properties to this object. These properties can be other objects, arrays, or just plain strings.

req.session.savedDoc = someObject; 
req.session.errors = ['someThing', 'anotherThing', 'thirdThing'];
req.session.message = 'someString'

If I later would like to erase all added properties of this object, what is the easiest/best way?

There must be a better way than this?

// Delete all session values
delete req.session.savedDoc;
delete req.session.errors;
delete req.session.message;
Anders Östman
  • 3,702
  • 4
  • 26
  • 48
  • See also performance comparison: [performance - How to quickly clear a JavaScript Object? - Stack Overflow](https://stackoverflow.com/questions/684575/how-to-quickly-clear-a-javascript-object) – user202729 Dec 24 '21 at 11:16

10 Answers10

163

@VisioN's answer works if you want to clear that specific reference, but if you actually want to clear an object I found that this works:

for (var variableKey in vartoClear){
    if (vartoClear.hasOwnProperty(variableKey)){
        delete vartoClear[variableKey];
    }
}
Dave Lugg
  • 2,326
  • 2
  • 15
  • 23
  • 34
    Why doesn't this answer have more upvotes... This actually clears the object, instead of creating a new object (old data still there if old object referenced by something). – basic6 May 03 '15 at 20:06
  • 2
    Yep! What @basic6 said. I ran into this issue today where creating a new object was breaking another reference that I had. This should be the correct answer. – James Manes Jul 07 '16 at 15:37
  • 2
    Is there any danger that some JavaScript implementation will get confused about deleting a property while enumerating properties? Or does the definition of the "in" enumeration specify precisely what should happen if properties are added and removed during the enumeration? – Adam Gawne-Cain Dec 31 '20 at 10:48
  • @AdamGawne-Cain There should be no such danger. The ECMAScript 5.1 standard section 12.6.4 (on for-in loops) says: "[Properties of the object being enumerated may be deleted during enumeration.](https://stackoverflow.com/a/19564686/227299)" – Ruan Mendes Mar 31 '22 at 19:26
  • Not to mention, in functional programming, you can't re-assign values, so clearing it by this method would be preferred. – tukool Apr 09 '23 at 13:25
92

There are two possible solutions to the problem:

Assign an empty object

req.session = {};

The garbage collector will clean the memory automatically. This variant is super fast and will work in most cases, however, you need to use it with caution, as it may keep the references to the objects in memory. This caveat is described in the TLDR section below.

Delete properties one-by-one

Object.keys(object).forEach(key => delete object[key]);

This will clean the object by going through every non-prototype property and deleting it. It's safer but slower. You need to decide if it makes sense for you to use it in a particular case.


TLDR

Any solution given above will do the job for the author in the current situation, as well as any other valid solution provided in this question. It mainly depends on the way how the developer wants to manipulate the deprecated data.

Session object may contain data that is linked by different variable, and setting a new empty object to req.session will not break the reference to the old data, so the old data will be available where it is still required. Although the correct way to keep old data is to clone the initial object, real-life scenarios can be different. Let's look at the following example:

req.session.user = { name: "Alexander" };  // we store an object in the session
var session = req.session;                 // save reference to the session in a variable
console.log( req.session, session );       // {user: Object}, {user: Object}

req.session = {};                          // let's replace session with a new object
console.log( req.session, session );       // {}, {user: Object}

We still can fetch old data from session variable but req.session is empty: here setting a new object works as a sort of alternative to deep cloning. The garbage collector will not remove data from the old req.session object as it is still referenced by the session variable.

Deep cleaning of the object with:

Object.keys(object).forEach(key => delete object[key]);

... will explicitly remove all values from the req.session object and, since session variable is linked to the same object, session will become empty as well. Let's see how it works:

req.session.user = { name: "Alexander" };  // we store an object in the session
var session = req.session;                 // save reference to the session in a variable
console.log( req.session, session );       // {user: Object}, {user: Object}

Object.keys(req.session).forEach(key => delete req.session[key]);
console.log( req.session, session );       // {}, {}

As you can see now, in both cases we get empty objects.

From speed and memory perspectives setting a new empty object will be much faster than cleaning the old object property by property, however memory-wise if the old data is still referenced somewhere, the new object approach won't free up memory that old data is consuming.

It's quite obvious that choosing the approach to take is mostly up to your coding scenario but in most cases req.session = {}; will do the job: it is fast and short. However, if you keep references to the original object in other variables, you may consider using deep implicit object properties deletion.

VisioN
  • 143,310
  • 32
  • 282
  • 281
  • 1
    I wonder its better to use req.session = null or the req.session = {}. Express site suggests to set it to null http://expressjs.com/api.html#cookieSession – Sriharsha Oct 11 '13 at 11:40
  • 63
    This is a useful answer, but I don't feel it is complete as it does not actually remove all properties from an object. If you have 2 references to the same object, req.session1 and req.session2 and assign req.session1 = {}. Then req.session2 remains the same with all of it's properties still defined – Theo Feb 19 '14 at 11:57
  • 19
    Although the result is an empty object, the object now references to a new point in memory - i.e. new object. That means if there was any double reference to that object, it is now gone. Bottom line - this is not emptying the object but rather replacing it with a new one. – Tomer Apr 16 '14 at 12:50
  • 9
    This does not answer the OP's question. – Pete Alvin Dec 07 '14 at 17:29
  • 1
    As others have pointed out, don't reassign if you (might) have references: `var session = req.session; req.session = {};` won't actually clear the object, session.message is still "someString". See [Dave Lugg's answer](http://stackoverflow.com/a/28570479/664132). – basic6 May 03 '15 at 20:03
  • 2) @Tomer Why do you think it's somewhat bad to reassign variable with a new object? If there is a reference to the old object the reference won't be broken, and you still will be able to access old data from the referencing variable instead of getting `undefined`. This is quite a valid solution which does the job, however if you need specifically to clear all referenced properties, you may need to implement deep `delete`. – VisioN Jun 01 '15 at 15:36
  • 1
    @VisioN I meant the opposite direction. That is, if the other object referencing this object, clearing the object will not clear all references. Consider: var t = {text: 'text'}; var f = t; t = {}; console.log(f); This will print the original object (rather then an empty object). – Tomer Jun 01 '15 at 17:56
  • @Tomer Yes, I clearly understand what you say and I meant exactly the same. My concern here is questioning: why do you think that it *should* print an empty object? Possibly you want to keep the actual "value" in the referencing variable. There is nothing mentioned about that in the question, and there is nothing wrong with it. Probably a tiny smell of bad architecture, but it's fine if it is done on purpose and you're able to control it. – VisioN Jun 01 '15 at 18:08
  • 2
    He thinks it should print an empty object because that's what the question is asking. Once you remove all properties from an object, you have an empty object. – Dave Lugg Jun 30 '15 at 04:46
  • 1
    "... and the garbage collector will do the rest automatically." This should come with a caveat, as pointed out by others already. If in other places there are references to the original object (var t = req.session;) the GC won't get rid of the old req.session; it'll stay in memory and t will still contain its values. If that's desired behavior, then fine, but the OP should at least understand the implications of this choice. The alternative is Dave Lugg's answer below. – Valorum Feb 01 '16 at 21:09
  • The question is merely "removing all properties from an object." The answer isn't sufficient if the object is a constant. – phillyslick Jun 01 '18 at 20:22
  • Suppose I don't have `req.session` but a local variable then setting it to `undefined` is good choice or empty object `{ }` ? – Farhan Ghumra Nov 29 '18 at 11:47
14

I can see only one correct solution for removing own properties from object:

for (var x in objectToClean) if (objectToClean.hasOwnProperty(x)) delete objectToClean[x];

If you want to use it more than once, you should create a cleaning function:

function deleteProperties(objectToClean) {
  for (var x in objectToClean) if (objectToClean.hasOwnProperty(x)) delete objectToClean[x];
}

For your case the usage would be:

deleteProperties(req.session);

This solution removes properties from the object wherever it's referenced and keeping the old reference.
Example:
Using empty object assignment:

var x = {a: 5};
var y = x;
x = {};    // x will be empty but y is still {a: 5}, also now reference is gone: x !== y

Using cleaning method:

var x = {a: 5};
var y = x;
deleteProperties(x);  // x and y are both empty and x === y
icl7126
  • 5,740
  • 4
  • 53
  • 51
6

If you want to delete all properties without touching methods you can use :

for(var k in req.session) if(!req.session[k].constructor.toString().match(/^function Function\(/)) delete req.session[k];
yent
  • 1,303
  • 1
  • 8
  • 10
  • Thanks ^^ the `constructor.toString()` thing is quite usefull, another one : if you want an improved version of `typeof`, try `Object.prototype.toString.call(thing).replace(/^\[.+\s(.+)\]$/g, '$1').toLowerCase()` :p – yent Oct 11 '13 at 12:04
  • But why not simply to use `typeof req.session[k] === 'function'` instead? – VisioN Oct 11 '13 at 12:06
  • Very true ... A while ago typeof only made difference between number, string, boolean, null and undefined, everything else returned "object", including function, so I got the habit of using something more precise ... Truth be told the code I gave is part of a bigger script I use in which I need to get the class name of an object whose class is defined using prototypes (`function foo() { this.a = 1; } foo.prototype.doThing = function ...`) ... – yent Oct 11 '13 at 12:17
  • `for(var k in req.session) if(!(req.session[k] instanceof Function)) delete req.session[k];` – Domi Feb 18 '15 at 13:59
5

You can use a map instead if you care about performance like so

const map = new Map()
map.set("first", 1)
map.set("second", 1)
map.clear()

This is a O(1) operation, so even if you have a huge object you do not need to iterate x times to delete the entries.

Gabriel Petersson
  • 8,434
  • 4
  • 32
  • 41
2

I've done it like this

var 
    i,
    keys = Object.keys(obj);
for(i = 0; i < keys.length; i++){
    delete obj[keys[i]];
}

You could add it to Object (prototype's not ideal here) - will be static.

Object.defineproperties(Object, {
    'clear': function(target){
        var 
            i,
            keys = Object.keys(target);
        for(i = 0; i < keys.length; i++){
            delete target[keys[i]];
        }
    }
});

Then you can clear random objects with

Object.clear(yourObj);

yourObj = {} replaces the reference to a new object, the above removes it's properties - reference is the same.

EnTr0cKs
  • 37
  • 6
  • I'd like to add that that those are somewhat costly operations - restructuring and that there probably are better ways to achieve one's goals. – EnTr0cKs Feb 19 '17 at 17:30
1

A good way to do this would be to loop through the return value of Object.getOwnPropertyNames(). This will catch both enumerable and hidden properties, but not symbols, and it already excludes inherited properties. Noteworthy, though, is that in order to remove a property using any method in these answers, that property must be configurable. If you want to catch symbols as well, you can add in Object.getOwnPropertySymbols().

const obj = Object.create( Object.prototype, {
    visibleProperty: {
        value: 'visibleProperty',
        enumerable: true,
        configurable: true,
    },
    hiddenProperty: {
        value: 'hiddenProperty',
        configurable: true,
    },
    [ Symbol( 'symbolProperty' ) ]: {
        value: 'symbolProperty',
        configurable: true,
    },
    visibleMethod: {
        value: () => 'visibleMethod',
        enumerable: true,
        configurable: true,
    },
    hiddenMethod: {
        value: () => 'hiddenMethod',
        configurable: true,
    },
    [ Symbol( 'symbolMethod' ) ]: {
        value: () => 'symbolMethod',
        configurable: true,
    },
} );

for( const key of Object.getOwnPropertyNames( obj ) ) delete obj[ key ];

console.log( Object.getOwnPropertyDescriptors( obj ) );

This will delete everything but the properties identified by symbols, so the last line will produce the following output:

{
    [Symbol(symbolProperty)]: {
        value: 'symbolProperty',
        writable: false,
        enumerable: false,
        configurable: true
    },
    [Symbol(symbolMethod)]: {
        value: [Function: value],
        writable: false,
        enumerable: false,
        configurable: true
    }
}
Jared Brandt
  • 203
  • 1
  • 7
  • [`Reflect.deleteProperty(obj, key)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/deleteProperty) might be even better than just `delete obj[ key ]`. – Peter Seliger May 16 '23 at 19:00
0

The naive object = {} method is okay for vanilla Object, but it deletes prototypes of custom objects.

This method produces an empty object that preserves prototypes, using Object.getPrototypeOf() and Object.create():

    emptyObj = Object.create(Object.getPrototypeOf(obj), {});

Example:

class Custom extends Object {
  custom() {}
}

let custom = new Custom();
custom.foo = "bar";
console.log(custom.constructor.name, custom);
// Custom {"foo": "bar"}

// naive method:
let objVanilla = {}
console.log(objVanilla.constructor.name, objVanilla);
// Object {}

// safe method:
objSafe = Object.create(Object.getPrototypeOf(custom), {});
console.log(objSafe.constructor.name, objSafe);
// Custom {}
terrymorse
  • 6,771
  • 1
  • 21
  • 27
0
let obj = { a: 1, b: 2, c: 3 };

// Get an array of all the keys of the object
let keys = Object.keys(obj);

// Loop through the keys and delete each property
for (let i = 0; i < keys.length; i++) {
  delete obj[keys[i]];
}

console.log(obj); // Output: {}
Synchro
  • 1,105
  • 3
  • 14
  • 44
-1

This script removes property recursively except for the data reported in vector.

You need the lodash library

-- Function:

function removeKeysExcept(object, keysExcept = [], isFirstLevel = true) {
        let arrayKeysExcept = [],
            arrayNextKeysExcept = {};
        _.forEach(keysExcept, (value, i) => {
            let j = value.split('.');
            let keyExcept = j[0];
            arrayKeysExcept.push(keyExcept);
            j.shift();
            if (j.length) {
                j = j.join('.');
                if (!arrayNextKeysExcept[keyExcept]) {
                    arrayNextKeysExcept[keyExcept] = [];
                }
                arrayNextKeysExcept[keyExcept].push(j);
            }
        })
        _.forEach(arrayNextKeysExcept, (value, key) => {
            removeKeysExcept(object[key], value, false);
        });
        if (isFirstLevel) {
            return;
        }
        Object.keys(object).forEach(function (key) {
            if (arrayKeysExcept.indexOf(key) == -1) {
                delete object[key];
            }
        });
    }

Run so:

-- Removes all properties except the first level and reported in the vector:

removeKeysExcept(obj, ['department.id','user.id']);

-- Removes all properties

removeKeysExcept(obj, ['department.id','user.id'], false);

-- Example:

let obj = {
    a: {
        aa: 1,
        ab: {
            aba: 21
        }
    },
    b: 10,
    c: {
        ca: 100,
        cb: 200
    }
};

removeKeysExcept(obj, ['a.ab.aba','c.ca']);
/*OUTPUT: {
    a: {
        ab: {
            aba: 21
        }
    },
    b: 10,
    c: {
        ca: 100,
    }
};*/

removeKeysExcept(obj, ['a.ab.aba','c.ca'], false); //Remove too firt level
/*OUTPUT: {
    a: {
        ab: {
            aba: 21
        }
    },
    c: {
        ca: 100,
    }
};*/

removeKeysExcept(obj);
/*OUTPUT: {b:10};*/

removeKeysExcept(obj, [], false); //Remove too firt level
/*OUTPUT: {};*/
João Júnior
  • 874
  • 5
  • 6