GetItem (‘ item’)是否优于 localStorage.item 或 localStorage [‘ item’] ?

我最近询问了 关于 LocalStorage 的问题。当项目还没有设置时,使用 JSON.parse(localStorage.item)JSON.parse(localStorage['item'])不能返回 NULL

然而,JSON.parse(localStorage.getItem('item')确实起作用了,而且事实证明,JSON.parse(localStorage.testObject || null)也起作用了。

其中一条评论基本上说 localStorage.getItem()localStorage.setItem()应该总是首选:

获取器和设置器提供了一致的、标准化的和 跨浏览器兼容的方式与 LS 应用程序接口工作,并应始终 比其他方式更受欢迎。-克里斯托弗

我开始喜欢使用 localStorage 的缩写点符号和括号符号,但是我很想知道其他人对此的看法。GetItem (‘ item’)是否优于 localStorage.item 或 localStorage [‘ item’] ,或者只要它们能够工作就可以了?

108651 次浏览

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.

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

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.

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