97

I recently asked a question about LocalStorage. Using JSON.parse(localStorage.item) and JSON.parse(localStorage['item']) weren't working to return NULL when the item hadn't been set yet.

However, JSON.parse(localStorage.getItem('item') did work. And it turns out, JSON.parse(localStorage.testObject || null) also works.

One of the comments basically said that localStorage.getItem() and localStorage.setItem() should always be preferred:

The getter and setter provide a consistent, standardised and crossbrowser compatible way to work with the LS api and should always be preferred over the other ways. -Christoph

I've come to like using the shorthand dot and bracket notations for localStorage, but I'm curious to know others' take on this. Is localStorage.getItem('item') better than localStorage.item or localStorage['item'] OR as long as they work are the shorthand notations okay?

Community
  • 1
  • 1
Mark Rummel
  • 2,920
  • 10
  • 37
  • 52
  • I believe Christoph has made his reasoning quite clear. `getItem` and `setItem` are the [standardised](http://www.w3.org/TR/webstorage/#storage) way of doing things. – Fabrício Matté Sep 28 '12 at 01:47
  • @FabrícioMatté The examples in the link you provided (under Introduction) use dot notation. Link: [W3C - Web Storage Introduction](http://dev.w3.org/html5/webstorage/#introduction) – Mark Rummel Sep 28 '12 at 02:08
  • 1
    I see. Little too sleepy to skim through those recommendations, but as this webstorage API is relatively new, I'd personally stick with the properly documented `getItem`/`setItem` methods. I'll read the specs later again, but the only fail-proof way of answering your question is doing throughout testing on all major browsers. – Fabrício Matté Sep 28 '12 at 02:13
  • 4
    The specification says "The supported property names on a Storage object are the keys of each key/value pair currently present in the list associated with the object." Doesn't that make `localStorage.item` standardized, too? – Barmar Sep 28 '12 at 02:57
  • 2
    @Barmar A little late reply, but after seeing so many dupes of this question and getting back here, I'll reply that you're absolutely right. However, I'll recommend again using `getItem`/`setItem` because these methods don't conflict with existing properties of the `localStorage` object. Example: `localStorage.setItem('getItem', 'blah'); console.log(localStorage.getItem('getItem'));` works, while `localStorage.getItem = 'blah';` will overwrite localStorage's `getItem` method. http://jsfiddle.net/DrquY/ – Fabrício Matté May 29 '13 at 23:42
  • @FabrícioMatté - Avoiding property name collisions is the first (and so far only) sensible reason I've seen for preferring the functional interface. – Ted Hopp Apr 09 '14 at 15:05
  • 1
    I still haven't seen an argument in favor of either approach that won me over. One does name/value pairs as they always have been. The other gives us nulls when we use get/set methods. I suppose if I were comparing against another list of values that had null for the optional values one would make more sense than the other but saying one or the other is 'preferred' when they're both in the spec is silly, IMO. Both approaches were made available for a reason. – Erik Reppen Apr 14 '14 at 21:15
  • @Erik Please take a look at [my answer](http://stackoverflow.com/a/24904863/1047823) and tell me what you think. – Christoph Jul 23 '14 at 08:02

4 Answers4

93

Both direct property access (localStorage.foo or localStorage['foo']) and using the functional interface (localStorage.getItem('foo')) work fine. Both are standard and cross-browser compatible.* According to the spec:

The supported property names on a Storage object are the keys of each key/value pair currently present in the list associated with the object, in the order that the keys were last added to the storage area.

They just behave differently when no key/value pair is found with the requested name. For example, if key 'foo' does not exist, var a = localStorage.foo; will result in a being undefined, while var a = localStorage.getItem('foo'); will result in a having the value null. As you have discovered, undefined and null are not interchangeable in JavaScript. :)

EDIT: As Christoph points out in his answer, the functional interface is the only way to reliably store and retrieve values under keys equal to the predefined properties of localStorage. (There are six of these: length, key, setItem, getItem, removeItem, and clear.) So, for instance, the following will always work:

localStorage.setItem('length', 2);
console.log(localStorage.getItem('length'));

Note in particular that the first statement will not affect the property localStorage.length (except perhaps incrementing it if there was no key 'length' already in localStorage). In this respect, the spec seems to be internally inconsistent.

However, the following will probably not do what you want:

localStorage.length = 2;
console.log(localStorage.length);

Interestingly, the first is a no-op in Chrome, but is synonymous with the functional call in Firefox. The second will always log the number of keys present in localStorage.

* This is true for browsers that support web storage in the first place. (This includes pretty much all modern desktop and mobile browsers.) For environments that simulate local storage using cookies or other techniques, the behavior depends on the shim that is used. Several polyfills for localStorage can be found here.

callum
  • 34,206
  • 35
  • 106
  • 163
Ted Hopp
  • 232,168
  • 48
  • 399
  • 521
14

The question is already quite old, but since I have been quoted in the question, I think I should say two words about my statement.

The Storage Object is rather special, it's an object, which provides access to a list of key/value pairs. Thus it's not an ordinary object or array.

For example it has the length attribute, which unlike the array length attribute is readonly and returns the number of keys in the storage.

With an array you can do:

var a = [1,2,3,4];
a.length // => 4
a.length = 2;
a // => [1,2]

Here we have the first reason to use the getters/setters. What if you want to set an item called length?

localStorage.length = "foo";
localStorage.length  // => 0
localStorage.setItem("length","foo");
// the "length" key is now only accessable via the getter method:
localStorage.length  // => 1
localStorage.getItem("length") // => "foo"

With other members of the Storage object it's even more critical, since they are writable and you can accidently overwrite methods like getItem. Using the API methods prevents any of these possible problems and provides a consistent Interface.

Also interesting point is the following paragraph in the spec (emphasized by me):

The setItem() and removeItem() methods must be atomic with respect to failure. In the case of failure, the method does nothing. That is, changes to the data storage area must either be successful, or the data storage area must not be changed at all.

Theoretically there should be no difference between the getters/setters and the [] access, but you never know...

Christoph
  • 50,121
  • 21
  • 99
  • 128
  • On the first point, damn near everything in JavaScript is writable and the localStorage API only has three properties I'm aware of. On the second, using the dot or bracket notation approaches you're still hitting some kind of native setter implementation since the values are auto-converted to strings no matter how you set them so it should have the same safeguards available. I've actually never hear of a persistent value getting corrupted in a client-side browser scenario before. I suspect even vanilla accessors typically have some kind of safeguard. – Erik Reppen Jul 28 '14 at 23:59
  • The point about name collision is excellent. The `length` property will not change (at least in Chrome and Firefox[\*]) if you call `localStorage.setItem("length", something);`, but you can retrieve `something` with `localStorage.getItem("length");`. Interestingly, assigning `localStorage.length = something;` in Chrome is a no-op, but in Firefox it will store `something` under the key `"length"` (which you can then only retrieve using the functional interface). [\*] Actually, in Firefox, the `length` property will change if the key `"length"` is not already in `localStorage`. – Ted Hopp Mar 13 '15 at 02:48
  • @ErikReppen - According to [the spec](http://www.w3.org/TR/webstorage/#the-storage-interface), `localStorage` has six predefined properties: `length`, `key`, `getItem`, `setItem`, `removeItem`, and `clear`. – Ted Hopp Mar 13 '15 at 03:05
2

I know it's an old post but since nobody actually mentioned performance I set up some JsPerf tests to benchmark it and as well as being a coherent interface getItem and setItem are also consistently faster than using dot notation or brackets as well as being much easier to read.

Here are my tests on JsPerf

Dave Mackintosh
  • 2,738
  • 2
  • 31
  • 40
  • ur jsPerf did not include brackets in its test. i've added them and run some tests, performance is browser-based. on chrome and firefox both, `getItem` and `setItem` were the slowest in each category, with dot being fastest on chrome and bracket being fastest on firefox. i also think 'being much easier to read' is entirely subjective ... yeah it states the function its performing, but anyone that has ever worked with object or array variables would know in half a second what's happening with dot / bracket. – PlantTheIdea Nov 14 '13 at 04:37
  • You're right, at the time of writing those tests the getters and setters were consistently faster than dot notation. Not the case anymore. When I get 5 minutes I'll come back and update this answer. Thanks for pointing that out. – Dave Mackintosh Nov 14 '13 at 10:57
0

As it was mentioned, there is almost no difference except of nonexisting key. The difference in performance varies depending on what browser/OS are you using. But it is not really that different.

I suggest you to use standard interface, just because it is a recommended way of using it.

Salvador Dali
  • 214,103
  • 147
  • 703
  • 753
  • _"I suggest you to use standard interface"_ - Both interfaces are specified in the standard. – Ted Hopp Apr 09 '14 at 14:59
  • @TedHopp I think that only setItem and getItem are [specified in the standard](http://dev.w3.org/html5/webstorage/#storage-0). – Salvador Dali Apr 09 '14 at 19:53
  • 2
    On the contrary. From the standard: _"The supported property names on a Storage object are the keys of each key/value pair currently present in the list associated with the object, in the order that the keys were last added to the storage area."_ – Ted Hopp Apr 09 '14 at 21:32