Local Storage
Learning outcomes:
- What is
localStorage
- Storing and retrieving data
- The
length
property andkey()
method - Removing some or all data
- The
storage
event
Introduction
As we discussed in the previous Storage Introduction chapter, the Storage
API has replaced cookies in storing data that is used solely for client-side purposes.
We also stated that the API has two mechanisms for storing data - one that holds onto data persistently and one that holds onto data for a browser session.
In this chapter we shall start with the former i.e the localStorage
object. We'll see all the basics of storing data, including how to set key-value pairs, update exisiting data in storage, delete some or all of the data and many more such utilities typical for storage interfaces.
So why we are wasting time here... Let's enroll!
What is localStorage
?
Essentially localStorage
is a property on the global window
object.
It's not an API on its own - rather it's based on the Storage
API we discussed in the previous chapter.
It allows one to store data persistently, without any expiration time.
Combining all these details:
localStorage
is a Storage
object that allows one to store data persistently.It's a property on window
, whose value is an object; an object that is an instance of the Storage
interface and that provides features to store data permanently on the client-side.
And this is the most eleborate it can get!
Storage
API stores data as key-value pairs.The key, which is a string, maps to a given value, which is once again a string.
localStorage
and sessionStorage
are instances of Storage
, whatever applies to Storage
obviously applies to both of them.Now all the experienced developers here will think: 'Isn't this just how objects work in JavaScript?'
And the answer is yes!
Storage
uses the same theory that's used behind JavaScript objects i.e keys map to given values; but with a few exceptions.
Unlike objects, values in the Storage
interface can only be strings. This is because, otherwise storing arrays or objects would require slightly more processing, and of course more memory.
Imagine how would a browser store an object as an object (not as a string) which has multiple properties, some of which point to objects themselves.
A browser can't store an object as an object - it has to serialize it i.e convert it into a string.
Likewise as a standard type, the Storage
API treats all keys and values as strings.
o.foo.bar.baz
), which isn't a surprise in JavaScript, the serializer will have to consider each subobject and convert that into a string as well.. It's just a lot of work!So as a standard,
Storage
allows keys and values to only be strings.If a key or value is not a string, then it's automatically coerced to one. We'll see all these type coercions taking place in real examples below.
Storing and retrieving data
Given that we now know what localStorage
exactly is, we can move over to see how to store data with it.
Well working with it is super easy!
There are two ways to add data to localStorage
:
- Use the old object-property syntax on the
localStorage
object, either in the dot notation (o.x
) or in the bracket notation (o["x"]
). - Use methods defined by the
Storage
interface to add data. This way is recommended for reasons which'll be discussed in the next section.
Anyways, let's consider an example.
Suppose you want to store the following variable permanently, using localStorage
:
var x = 10;
The way you can do so is shown below, first using the object-property syntax:
localStorage.x = 10; // dot notation
/* same as
localStorage["x"] = 10; // bracket notation
*/
This statement, in the dot notation, defines a property x
on the localStorage
object with a value of 10
.
This value will be stored by the browser, together with the key x
in local storage. The key will map to the value "10"
.
localStorage.x
but what gets stored is "10"
- the number 10
stringified. This is because the number 10
is converted into a string before being stored.Now let's access these values using the same object property syntax:
console.log(localStorage.x); // "10"
As you would agree, this notation definitely feels more natural to work with, but the thing is that it has some pitfalls to it, and is generally not recommended. We'll shortly see why?
The second way to accomplish all this logic is by using two methods on the localStorage
object - setItem()
and getItem()
.
It's time for you to guess a deal!
Make a logical guess on how many arguments does the method setItem()
require and in which order.
- 1 argument; key
- 1 argument; value
- 2 arguments; key and then value
- 2 argument; value and then key
The method setItem(key, value)
takes a key and a value and puts the key-value pair in storage.
Similarly, the method getItem(key)
takes a key and returns its corresponding value, or else the value null
if no such key exists.
Consider the following code:
localStorage.setItem("x", 10);
This sets a key on the localStorage
object that maps to the value "10"
.
To retrieve this value we pass the key "x"
to the method getItem()
:
localStorage.getItem("x"); // "10"
And so in this way we can store data in local storage and then later on retrieve it for further use.
Just specify a key and/or a value and you're all set to go!
What will the following code log in the console?
var o = {x: 10};
localStorage.setItem("o", o);
console.log(localStorage.getItem("o"));
- The object
{x: 10}
- The string
"{x: 10}"
- The string
"[object Object]"
The length property
As with Array
, NodeList
, HTMLCollection
and arguments
objects, the length
property on localStorage
holds the number of keys on the object.
When localStorage
has no data in it, the value of length
is effectively equal to 0
.
Consider the following code where we first create a key-value pair on localStorage
and then log its length
:
localStorage.a = "Hello World!";
console.log(localStorage.length); // 1
localStorage
has no data in it!Similarly, suppose that before executing the code below, localStorage
has 2 key-value pairs already stored in it - one is the key a
and the other is the key b
.
Now when we execute the code below, obviously you can predict yourself what will length
be equal to.
localStorage.c = "foo";
localStorage.d = "bar";
console.log(localStorage.length); // 4
It'll be equal to 4
, since now we've added two further keys in localStorage
.
Removing data
There may come certain occasions where one would want to remove a given peice of data fro localStorage
.
How we can do this is once again split into two categories - the object-property syntax and a method of the Storage
API.
First let's see how to use the former.
Recall, how to delete a property from a given object.. We use the delete
keyword followed by the usual property-access expression.
This is exactly how we delete a property from localStorage
, in the object-property syntax.
In the code below we remove the same key "x"
that we created above (holding the value "10"
) using dot notation:
delete localStorage.x;
This is effectively the same as:
delete localStorage["x"];
The delete
operator returns true
when it is successful in removing a property from a given object. In this case, it will surely evaluate to true
.
delete
keyword because it isn't consistent at all. For example, see the following code: delete localStorage.noSuchProperty; // true
localStorage
but nonetheless delete
returns true
.Moving on, the methodical way to remove data from storage is to use removeItem()
.
The method removeItem(key)
takes in a key and removes its corresponding data from storage.
Following is an illustration:
localStorage.removeItem("x");
This code removes the data corresponding to the key "x"
, along with the key itself (obviously), from storage.
Note that unlike the delete
keyword, removeItem()
does NOT return any Boolean to indicate whether it was successful or not. Rather it always returns undefined
.
Clearing everything
Besides deleting some data from storage, another common concern of applications is to delete all data from storage.
Fortunately there is only one straightforward way to accomplish this and that is using the method clear()
.
Simply call the method clear()
on a Storage
object and it'll remove all its data - no arguments are required.
Take a look at the code below:
localStorage.a = 10;
localStorage.b = 10;
console.log(localStorage.length); // 2
// clear away everything
localStorage.clear();
console.log(localStorage.length); // 0
First we create two key-value pairs on localStorage
and then log length
, which, as expected, returns 2
.
After this we call clear()
to remove all data from localStorage
, and then finally log length
again. This time it returns 0
which clearly confirms the job of clear()
- remove everything.
Now you wouldn't have realized the fact that in the discussion above, you've already witnessed one pitfall of using the object-property syntax to work with the Storage
API.
That is, it isn't possible to remove everything from storage using the property syntax - there isn't any single statement which can do this!
Or better to say, it'll be a painful task to accomplish this manually using a loop, the delete
keyword, the length
property and the key()
method (which we'll see below); yet with absolutely no guarantees of cross-browser support!
To boil it down, using methods is the right way to take!
Retrieving keys
In addition to all the useful methods we've seen above, the Storage
interface provides another method key()
to allow developers to obtain an nth key from storage.
Just pass in a numeric index to key()
and it will throw out the key sitting at that very index.
Remember that this does not at all mean that localStorage
stores ket-value pairs in an array where elements can be accessed via an index.
The method key()
is given just for convenience - to be able to retrieve a given key from a Storage
object. That's it!
How browsers implement this method, and in which order do they store keys is a matter that varies from browser-to-browser; and thereby it's recommended to never solely rely on the order in which keys are stored!
Anyways, a typical use case of key()
can be to get all the keys from a given storage object, iteratively, in a for
loop, handled by the length
property.
Shown below is an example:
localStorage.a = 10;
localStorage.b = 50;
for (var i = 0, len = localStorage.length; i < len; i++) {
console.log(localStorage.key(i));
}
This code will merely log all the keys currently stored in the localStorage
object.
localStorage
is unpredicatable, at least for those who aren't browser developers. See how "b"
is logged before "a"
in the example above.Therefore, it is recommended to never rely on the order of keys of
localStorage
!However, note that this isn't the only way to retrieve all the keys from localStorage
. Another way which cuts down this loop boilerplate is the method Object.getOwnPropertyNames()
.
Give the method an object, and it'll return an array of all the keys of the object.
Following we give this method the localStorage
object and likewise get an array returned holding all its keys:
localStorage.a = 10;
localStorage.b = 50;
var keys = Object.getOwnPropertyNames(localStorage);
console.log(keys); // ["b", "a"]
The storage event
When two windows pointing to the same local storage location are opened simultaneously and a storage query happens in the meanwhile in one of them, a storage
event is dispatched.
Except for the window where the actual query takes place, all other open windows (pointing to the same storage location) receive the storage
event.
To handle this event we can either use the onstorage
handler on window
or the addEventListener()
method, passing it "storage"
as the first argument.
The storage
event is an instance of the StorageEvent
interface which exposes the following properties:
oldValue
- holds the old value of a given key that has assigned some other value.newValue
- holds the new value of a given key that has been assigned some other valuekey
- holds the key that has received a change.storageArea
- points to thelocalStorage
object, in this case.url
- holds the url of the page where the storage query took place.
Below we illustrate how the storage
event works on a basic level. It's advised that you follow the given instructions carefully in order to understand everything more clearly.
We'll start by creating an HTML file with the following JavaScript code to store some data in our localStorage
object:
localStorage.x = 10;
Go on and visit the following link to execute this right now.
After this, we'll create another HTML page with the following JavaScript code, to handle the storage
event:
window.onstorage = function(e) {
console.log(e);
}
storage
event only fires on the window
element - no other object!With this in place, it's now time to open both these pages simultaneously in our browser. Assuming you've opened the link above, just open the link below as well, and you are good to go.
And the game begins... Woah! Yayyy!
Open the tab for first HTML page where the localStorage.x = 10
statement is written. Go to the console and change the value of the key x
to some value other than 10. (You gotta change it!)
Once you do this, go to the second window (where the storage
event is being handled) and open the console. You'll witness a StorageEvent
object been logged.
For those of who don't have access to the console, you can still witness all this action in the following two links.
In the first link you can change data on localStorage
by pressing a button whereas in the second link you can witness the change, as it handles the storage
event.
localStorage
in any other window. This is because if, otherwise, it's not opened then the storage
event would be lost!Now if you're unable to perform and understand any of the steps above, here's the deal!
localStorage
object in one window; by either adding, modifying or deleting data; and then hear for the storage
event in another window.The same window where the storage query happens never gets the storage
event - we ought to open two tabs to witness all this action!
Spread the word
Think that the content was awesome? Share it with your friends!
Join the community
Can't understand something related to the content? Get help from the community.