LocalStorage.getItem ('item') лучше, чем localStorage.item или localStorage ['item']?

85

Недавно я задал вопрос о 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 api и всегда должны быть предпочтительнее других способов. - Кристоф

Мне нравится использовать сокращенные обозначения точек и скобок для localStorage, но мне любопытно узнать, как другие относятся к этому. Является ли localStorage.getItem ('item') лучше, чем localStorage.item или localStorage ['item'], ИЛИ пока они работают, допустимы сокращенные обозначения?

Марк Раммел
источник
Я считаю, что Кристоф довольно ясно изложил свои рассуждения. getItemи setItemявляются стандартизированным способом ведения дел.
Fabrício Matté
1
Понимаю. Слишком сонно, чтобы просмотреть эти рекомендации, но поскольку этот API веб-хранилища относительно новый, я лично придерживаюсь правильно задокументированных getItem/ setItemметодов. Я прочту спецификации позже, но единственный надежный способ ответить на ваш вопрос - это тестирование во всех основных браузерах.
Fabrício Matté
4
В спецификации говорится: «Поддерживаемые имена свойств в объекте Storage - это ключи каждой пары ключ / значение, присутствующей в настоящее время в списке, связанном с объектом». Разве это localStorage.itemтоже не стандартизировано?
Barmar
2
@Barmar Немного запоздалый ответ, но, увидев так много дураков этого вопроса и вернувшись сюда, я отвечу, что вы абсолютно правы. Однако я снова рекомендую использовать getItem/, setItemпотому что эти методы не конфликтуют с существующими свойствами localStorageобъекта. Пример: localStorage.setItem('getItem', 'blah'); console.log(localStorage.getItem('getItem'));работает, а метод localStorage.getItem = 'blah';localStorage будет перезаписан getItem. jsfiddle.net/DrquY
Фабрисио Матте
1
Я до сих пор не видел аргументов в пользу того или иного подхода, которые бы меня убедили. Пары имя / значение создаются, как всегда. Другой дает нам нули, когда мы используем методы get / set. Я полагаю, что если бы я сравнивал с другим списком значений, у которых было null для необязательных значений, одно имело бы больше смысла, чем другое, но говорить, что один или другой является «предпочтительным», когда они оба указаны в спецификации, глупо, ИМО. Оба подхода были доступны по какой-то причине.
Эрик Реппен

Ответы:

84

И прямой доступ к свойствам ( localStorage.itemили localStorage['item']), и использование функционального интерфейса ( localStorage.getItem('item')) работают нормально. Оба являются стандартными и совместимы с несколькими браузерами. * Согласно спецификации :

Имена поддерживаемых свойств объекта Storage - это ключи каждой пары ключ / значение, присутствующей в настоящее время в списке, связанном с объектом, в том порядке, в котором ключи были добавлены в область хранения в последний раз.

Просто они ведут себя по-другому, когда не найдено пары ключ / значение с запрошенным именем. Например, если ключ 'item'не существует, var a = localStorage.item;будет aиметь значение undefined, а значение var a = localStorage.getItem('item');будет aиметь значение null. Как вы обнаружили, undefinedи nullне являются взаимозаменяемыми в JavaScript / ECMAScript. :)

РЕДАКТИРОВАТЬ: Как указывает Кристоф в своем ответе , функциональный интерфейс - это единственный способ надежно хранить и извлекать значения под ключами, равными предопределенным свойствам localStorage. (Есть шесть из них: length, key, setItem, getItem, removeItem, и clear.) Так, например, следующий будет всегда работа:

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

Обратите внимание, в частности, что первый оператор не повлияет на свойство localStorage.length(за исключением, возможно, увеличения его, если ключ 'length'уже не был вlocalStorage ). В этом отношении спецификация кажется внутренне противоречивой.

Однако следующее, вероятно, не даст того, что вы хотите:

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

Интересно, что первый из них не работает в Chrome, но является синонимом функционального вызова в Firefox. Второй всегда будет записывать количество ключей, присутствующих вlocalStorage .

* Это верно для браузеров, которые в первую очередь поддерживают веб-хранилище. (Сюда входят почти все современные настольные и мобильные браузеры.) Для сред, имитирующих локальное хранилище с помощью файлов cookie или других методов, поведение зависит от используемой прокладки. Несколько polyfills для localStorageмогут быть найдены здесь .

Тед Хопп
источник
12

Вопрос уже довольно старый, но, поскольку я был процитирован в вопросе, я думаю, что должен сказать два слова о своем заявлении.

Объект хранилища довольно особенный, это объект, который предоставляет доступ к списку пар ключ / значение. Таким образом, это не обычный объект или массив.

Например, у него есть атрибут длины, который, в отличие от атрибута длины массива, доступен только для чтения и возвращает количество ключей в хранилище.

С массивом вы можете:

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

Здесь у нас есть первая причина использовать геттеры / сеттеры. Что делать, если вы хотите установить элемент с именем 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"

С другими членами объекта Storage это еще более критично, поскольку они доступны для записи, и вы можете случайно перезаписать такие методы, как getItem . Использование методов API предотвращает любые из этих возможных проблем и обеспечивает согласованный интерфейс.

Также интересным моментом является следующий абзац в спецификации (выделенный мной):

Методы setItem () и removeItem () должны быть атомарными в отношении сбоя. В случае неудачи метод ничего не делает. То есть изменения в области хранения данных должны быть либо успешными, либо область хранения данных не должна изменяться вообще.

Теоретически не должно быть разницы между геттерами / сеттерами и []доступом, но мало ли ...

Кристоф
источник
По первому пункту, почти все в JavaScript доступно для записи, а API localStorage имеет только три свойства, о которых я знаю. Во-вторых, при использовании подходов с точечной или скобочной нотацией вы по-прежнему сталкиваетесь с какой-то собственной реализацией установщика, поскольку значения автоматически преобразуются в строки независимо от того, как вы их устанавливаете, поэтому для них должны быть доступны те же меры безопасности. На самом деле я никогда раньше не слышал о повреждении постоянного значения в сценарии клиентского браузера. Я подозреваю, что даже ванильные аксессуары обычно имеют какую-то защиту.
Эрик Реппен
Дело о коллизии имен отличное. lengthСвойство не изменится (по крайней мере , в Chrome и Firefox [*]) , если вы звоните localStorage.setItem("length", something);, но вы можете получить somethingс localStorage.getItem("length");. Интересно, что назначение localStorage.length = something;в Chrome не работает, но в Firefox оно будет храниться somethingпод ключом "length"(который затем вы можете получить только с помощью функционального интерфейса). [*] На самом деле в Firefox lengthсвойство изменится, если ключ "length"еще не введен localStorage.
Тед Хопп,
@ErikReppen - Согласно спецификации , localStorageимеет шесть предопределенных свойств: length, key, getItem, setItem, removeItem, и clear.
Тед Хопп,
1

Я знаю, что это старый пост, но поскольку никто на самом деле не упомянул производительность, я настроил несколько тестов JsPerf для его тестирования, а также для того, чтобы он был согласованным интерфейсом getItemиsetItem они также постоянно быстрее, чем использование точечной нотации или скобок, а также их намного легче читать.

Вот мои тесты на JsPerf

Дэйв Макинтош
источник
ur jsPerf не включил скобки в свой тест. Я добавил их и провел несколько тестов, производительность зависит от браузера. на Chrome и Firefox оба, getItemи setItemбыли самыми медленными в каждой категории, причем точка была самой быстрой в Chrome, а скобка была самой быстрой в Firefox. Я также думаю, что «намного легче читать» - это полностью субъективно ... да, в нем говорится о выполняемой функции, но любой, кто когда-либо работал с объектами или переменными массива, узнает за полсекунды, что происходит с точкой / скобкой.
PlantTheIdea
Вы правы, на момент написания этих тестов геттеры и сеттеры всегда были быстрее, чем точечная нотация. Это уже не так. Когда у меня будет 5 минут, я вернусь и обновлю этот ответ. Спасибо что подметил это.
Дэйв Макинтош
0

Как уже было сказано, разницы почти нет, кроме несуществующего ключа. Разница в производительности варьируется в зависимости от того, какой браузер / ОС вы используете. Но на самом деле это не так уж и сложно.

Я предлагаю вам использовать стандартный интерфейс просто потому, что это рекомендуемый способ его использования.

Сальвадор Дали
источник
«Предлагаю вам использовать стандартный интерфейс» - Оба интерфейса указаны в стандарте.
Тед Хопп
@TedHopp Я думаю, что в стандарте указаны только setItem и getItem .
Сальвадор Дали
2
Наоборот. Из стандарта: «Поддерживаемые имена свойств в объекте Storage - это ключи каждой пары ключ / значение, присутствующей в настоящее время в списке, связанном с объектом, в том порядке, в котором ключи были добавлены в область хранения в последний раз».
Тед Хопп