40

I have stored several key value pairs which contains certain encrypted login information using HTML5 localstorage variables. I have added a unique prefix to all key names say TM_loginname . Now I want to clear all the localstorage key-value pairs whose key starts with prefix TM_. PS: I tried sessionstorage too, but it clears only when browser is closed.

Trishul
  • 998
  • 1
  • 7
  • 17

6 Answers6

60

Removing element while iterating is unsafe, so create an array to hold the keys that need to be removed. Then, iterate over that array to remove them:

var arr = []; // Array to hold the keys
// Iterate over localStorage and insert the keys that meet the condition into arr
for (var i = 0; i < localStorage.length; i++){
    if (localStorage.key(i).substring(0,3) == 'TM_') {
        arr.push(localStorage.key(i));
    }
}

// Iterate over arr and remove the items by key
for (var i = 0; i < arr.length; i++) {
    localStorage.removeItem(arr[i]);
}
RonyHe
  • 890
  • 8
  • 11
  • Please always explain your code and don't simply throw code at us. – dirkk Jul 03 '14 at 12:23
  • Can you reference why _"removing an element while iterating is unsafe"_? – Etheryte Jul 03 '14 at 12:28
  • Thank you for the comment dirkk, I'm new to this and I appreciate the guidance. Nit, I used two loops to avoid removing elements while, iterating which seems unsafe. Was this avoidable? – RonyHe Jul 03 '14 at 12:29
  • Let's say we have `var someArr = ['TM_a', 'TM_b' 'c'];`. When our loop index, i, is 0 we'll remove 'TM_a', which shifts the rest of the elements 'to the left'. Meaning, our loop index is 1, but 'TM_b' is currently in `someArr[0]`. After the iteration 'TM_a' is still in the array and we didn't achieve our goal. Now, there are ways to avoid this in JS, but seeing as our API to localStorage is with an interface, it seems prudent to use it instead of risking unpredictable results. If someone is more deeply familiar with the structure of localStorage, perhaps they have a better way? – RonyHe Jul 03 '14 at 13:22
  • 3
    **more:** `(localStorage.key(i).indexOf(path_key) >= 0)` also works, or use a variable to make it more scalable: `...substring(0, prefix.length) == prefix` – maguri Feb 14 '18 at 12:05
  • Nit, you modify array which is iterated. You can get out of bounds bug. People wrote that iterating backwards and removal is safe – Kamil Orzechowski Feb 14 '18 at 17:38
20

A more modern (ES2017) solution is as follows:

Object.entries(localStorage).map(
        x => x[0] # get keys
    ).filter(
        x => x.substring(0,3)=="TM_"
    ).map(
        x => localStorage.removeItem(x))

EDIT

Taken from the comments:

Object.keys(localStorage)
 .filter(x =>
    x.startsWith('TM_'))
 .forEach(x => 
    localStorage.removeItem(x))
rmcsharry
  • 5,363
  • 6
  • 65
  • 108
tbenst
  • 804
  • 8
  • 16
  • 1
    The last operation in this pipeline might be better off being a `forEach` instead of a `map`. Map in this case yields nothing as `removeItem` returns `undefined`. – Milan Velebit Apr 09 '21 at 21:31
  • agreed, forEach is preferable since avoids unnecessary allocation. thx! – tbenst Apr 11 '21 at 00:49
  • 2
    Would `x.startsWith` rather than `x.substring` be cleaner? – Tom Jul 26 '21 at 08:06
  • 2
    Since you need the keys, you can use Object.keys(localStorage) instead `Object.keys(localStorage).filter(x => x.startsWith('TM_')).forEach(x => localStorage.removeItem(x))` – Andy1210 Jul 28 '21 at 09:11
11

Using lodash. Enjoy.

_.forIn(window.localStorage, (value: string, objKey: string) => {
    if (true === _.startsWith(objKey, 'TM_')) {
        window.localStorage.removeItem(objKey);
    }
});
Diego Laciar
  • 2,898
  • 3
  • 14
  • 8
4

save to localStorage using key = pref + version

function remLSPref(pref, newName) {
    for (var key in localStorage) {
        if (key.indexOf(pref) == 0) {
            if (key != newName) {
                localStorage.removeItem(key);
            }
        }
    }
}

and use like this:

var pref = 'myid_';
var key = pref + ver;

// rem old ls
remLSPref(pref, key);
Omu
  • 69,856
  • 92
  • 277
  • 407
1

You can either:

Community
  • 1
  • 1
Etheryte
  • 24,589
  • 11
  • 71
  • 116
  • Actually I am doing this(using loop) currently but I was looking for any better alternate than looping... – Trishul Jul 03 '14 at 11:35
  • Even if there was a built-in method to do something akin to this, it would still use a loop. The only question here is how large of a loop you want to run over, on a complex site, localStorage may be quite large and it would be more reasonable to keep a list of the items yourself. On a small site, the performance difference isn't likely all that large if you don't want to track the items manually. – Etheryte Jul 03 '14 at 12:28
  • Thanks Nit, it seems I have to continue to store the keys and eventually clear them at logout – Trishul Jul 04 '14 at 05:00
1

Adapting the tip of github:

findLocalItems(query) {
var i,
  results = [];
for (i in localStorage) {
  if (localStorage.hasOwnProperty(i)) {
    if (i.match(query) || (!query && typeof i === 'string')) {
      var value = JSON.parse(localStorage.getItem(i));
      results.push({ key: i, val: value });
    }
  }
}
return results;  }

And after, calling the function:

var keysFounded = findLocalItems(key);
if (keysFounded && keysFounded.length > 0) {
  keysFounded.forEach(k => {
    localStorage.removeItem(k.key);
  });
}
Nuno Ribeiro
  • 2,487
  • 2
  • 26
  • 29