Я хотел бы сохранить объект JavaScript в HTML5 localStorage
, но мой объект, по-видимому, преобразуется в строку.
Я могу хранить и извлекать примитивные типы и массивы JavaScript с использованием localStorage
, но объекты, похоже, не работают. Должны ли они?
Вот мой код:
var testObject = { 'one': 1, 'two': 2, 'three': 3 };
console.log('typeof testObject: ' + typeof testObject);
console.log('testObject properties:');
for (var prop in testObject) {
console.log(' ' + prop + ': ' + testObject[prop]);
}
// Put the object into storage
localStorage.setItem('testObject', testObject);
// Retrieve the object from storage
var retrievedObject = localStorage.getItem('testObject');
console.log('typeof retrievedObject: ' + typeof retrievedObject);
console.log('Value of retrievedObject: ' + retrievedObject);
Консольный вывод
typeof testObject: object
testObject properties:
one: 1
two: 2
three: 3
typeof retrievedObject: string
Value of retrievedObject: [object Object]
Мне кажется, что setItem
метод преобразует входные данные в строку перед ее сохранением.
Я вижу такое поведение в Safari, Chrome и Firefox, поэтому я предполагаю, что это мое неправильное понимание спецификации веб-хранилища HTML5 , а не ошибка или ограничение для конкретного браузера.
Я попытался разобраться в алгоритме структурированного клонирования , описанном в http://www.w3.org/TR/html5/infrastructure.html . Я не до конца понимаю, о чем идет речь, но, возможно, моя проблема связана с тем, что свойства моего объекта не перечисляются (???)
Есть ли легкий обходной путь?
Обновление: W3C в конечном итоге изменил свое мнение о спецификации структурированных клонов и решил изменить спецификацию в соответствии с реализациями. См. Https://www.w3.org/Bugs/Public/show_bug.cgi?id=12111 . Таким образом, этот вопрос больше не является действительным на 100%, но ответы все еще могут представлять интерес.
источник
Ответы:
Глядя на документацию Apple , Mozilla и Mozilla снова , кажется, что функциональность ограничена, чтобы обрабатывать только пары ключ / значение строки.
Обходной может быть stringify ваш объект перед сохранением, а затем разобрать его , когда вы извлекаете его:
источник
JSON.stringify()
расширяет ссылочный объект до его полного «содержимого» (неявно строкового) в объекте, который мы строковым образом. См .: stackoverflow.com/a/12659424/2044940Незначительное улучшение варианта :
Из - за оценки короткого замыкания ,
getObject()
будет немедленно вернуться ,null
еслиkey
не в хранилище. Он также не будет генерироватьSyntaxError
исключение, еслиvalue
есть""
(пустая строка;JSON.parse()
не может обработать это).источник
var userObject = { userId: 24, name: 'Jack Bauer' };
и установить его.localStorage.setObject('user', userObject);
Затем вернуть его из хранилища.userObject = localStorage.getObject('user');
Вы можете даже сохранить массив объектов, если хотите.key
не в локальном хранилище,window.localStorage.getItem(key)
возвращаетсяnull
- это не бросать «Неправомерный доступ» исключение - иJSON.parse(null)
возвращается ,null
как хорошо - это не сгенерирует исключение либо, ни в Chromium 21 , ни в ES 5.1 раздела 15.12.2 , поскольку ,String(null) === "null"
которые могут интерпретироваться как литерал JSON .""
(пустую строку) раньше. Потому что он преобразует тип вfalse
иJSON.parse("")
, что вызоветSyntaxError
исключение, не вызывается.Возможно, вам будет полезно расширить объект Storage с помощью этих удобных методов:
Таким образом, вы получаете функциональность, которая вам действительно нужна, хотя под API поддерживаются только строки.
источник
localStorage.setObject
.getObject()
вызоветSyntaxError
исключение, если сохраненное значение есть""
, потому чтоJSON.parse()
не может обработать это. Смотрите подробности в моем редактировании ответа Гурии.Расширение объекта Storage является отличным решением. Для своего API я создал фасад для localStorage и затем проверяю, является ли он объектом или нет, при установке и получении.
источник
data.set('username': 'ifedi', 'fullname': { firstname: 'Ifedi', lastname: 'Okonkwo'});
?Stringify не решает всех проблем
Кажется, что ответы здесь не охватывают все типы, которые возможны в JavaScript, поэтому вот несколько коротких примеров того, как правильно обращаться с ними:
Я не рекомендую хранить функции, потому что
eval()
зло может привести к проблемам с безопасностью, оптимизацией и отладкой. В основном,eval()
никогда не должен использоваться в коде JavaScript.Частные участники
Проблема с использованием
JSON.stringify()
для хранения объектов заключается в том, что эта функция не может сериализовать закрытые члены. Эта проблема может быть решена путем перезаписи.toString()
метода (который вызывается неявно при хранении данных в веб-хранилище):Циркулярные ссылки
Другая проблема, с которой
stringify
нельзя справиться, это циклические ссылки:В этом примере
JSON.stringify()
будет выданоTypeError
«Преобразование круговой структуры в JSON» . Если должно поддерживаться хранение циклических ссылок, можно использовать второй параметрJSON.stringify()
:Однако поиск эффективного решения для хранения циклических ссылок в значительной степени зависит от задач, которые необходимо решить, и восстановление таких данных также не является тривиальным.
В SO уже есть вопрос, касающийся этой проблемы: Stringify (преобразовать в JSON) объект JavaScript с циклической ссылкой
источник
Существует отличная библиотека, которая объединяет многие решения, поэтому она поддерживает даже старые браузеры, называемые jStorage.
Вы можете установить объект
И получить это легко
источник
Теоретически возможно хранить объекты с функциями:
Однако сериализация / десериализация функций ненадежна, поскольку зависит от реализации .
источник
c.f[k] = escape(a[k]);
на Unicode-safec.f[k] = encodeURIComponent(a[k]);
иeval('b.' + k + ' = ' + unescape(data.f[k]));
наb[k] = eval("(" + decodeURIComponent(data.f[k]) + ")");
. Скобки требуются, потому что ваша функция, если она правильно сериализована, скорее всего, будет анонимной, что не является допустимым / оператором / (поэтомуeval()
) выдаетSyntaxError
исключение в противном случае).typeof
это оператор , не пишите это так, как если бы это была функция. Заменитьtypeof(a[k])
наtypeof a[k]
.for
-in
не был отфильтрован по собственным свойствам. 3. Стиль кода, включая ссылки, был противоречивым.the use and placement of white space, line terminators, and semicolons within the representation String is implementation-dependent.
я не вижу никаких функциональных различий.Note *in particular* that …
. Но спецификация возвращаемого значения начинается сAn implementation-dependent representation of the function is returned. This representation has the syntax of a FunctionDeclaration.
Возвращаемое значение может бытьfunction foo () {}
- при условии соответствующей реализации.Я пришел к этому сообщению после того, как нажал на другое сообщение, которое было закрыто как дубликат этого - под названием «Как сохранить массив в localalstorage?». Это нормально, за исключением того, что ни один из потоков на самом деле не дает полного ответа о том, как вы можете поддерживать массив в localStorage - однако мне удалось разработать решение на основе информации, содержащейся в обоих потоках.
Так что, если кто-то еще хочет иметь возможность помещать / перемещать / сдвигать элементы в массиве, и он хочет, чтобы этот массив хранился в localStorage или действительно sessionStorage, вот вам:
пример использования - хранение простых строк в массиве localStorage:
пример использования - хранение объектов в массиве sessionStorage:
Распространенные методы манипулирования массивами:
источник
Рекомендуем использовать библиотеку абстракций для многих функций, обсуждаемых здесь, а также для лучшей совместимости. Много вариантов:
источник
Вы можете использовать localDataStorage для прозрачного хранения типов данных javascript (Array, Boolean, Date, Float, Integer, String и Object). Он также обеспечивает упрощенную обфускацию данных, автоматически сжимает строки, облегчает запрос по ключу (имени), а также по запросу (ключу) и помогает обеспечить сегментированное общее хранилище в том же домене с помощью префикса ключей.
[ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ] Я являюсь автором утилиты [/ ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ]
Примеры:
Как видите, примитивные значения соблюдаются.
источник
Другой вариант будет использовать существующий плагин.
Например, persisto - это проект с открытым исходным кодом, который предоставляет простой интерфейс для localStorage / sessionStorage и автоматизирует сохранение для полей формы (ввод, переключатели и флажки).
(Отказ от ответственности: я автор.)
источник
localStroage
; exp:var lsh = new localStorageHelper(); lsh.setItem('bob', 'bill');
Также включает в себя события.Вы можете использовать ejson для хранения объектов в виде строк.
Вот моя оболочка localStorage с использованием ejson
https://github.com/UziTech/storage.js
Я добавил несколько типов в свою оболочку, включая регулярные выражения и функции
источник
Я сделал еще одну минималистичную оболочку, содержащую всего 20 строк кода, чтобы использовать ее так, как следует:
https://github.com/zevero/simpleWebstorage
источник
Для пользователей Typescript, желающих установить и получить типизированные свойства:
Пример использования :
источник
https://github.com/adrianmay/rhaboo - слой сахара localStorage, который позволяет писать такие вещи:
Он не использует JSON.stringify / parse, потому что это будет неточно и медленно для больших объектов. Вместо этого каждое значение терминала имеет свою собственную запись localStorage.
Вы можете догадаться, что я могу иметь какое-то отношение к rhaboo.
источник
Вот некоторая расширенная версия кода, размещенная @danott
Также будет реализовано удаление значения из localstorage и показано, как добавить слой Getter и Setter вместо
localstorage.setItem(preview, true)
ты можешь написать
config.preview = true
Ладно, вот и пошли
Ну, вы можете лишить псевдонимы части
.bind(...)
. Тем не менее, я просто вставил это, потому что об этом очень приятно знать. Я потратил несколько часов, чтобы понять, почему простойget = localStorage.getItem;
не работаетисточник
Я сделал вещь, которая не ломает существующие объекты хранения, но создает оболочку, чтобы вы могли делать то, что вы хотите. В результате получается обычный объект, без методов, с доступом, как у любого объекта.
То, что я сделал.
Если вы хотите, чтобы 1
localStorage
свойство было волшебным:Если вам нужно несколько:
Все, что вы делаете
prop
, или объекты внутриstorage
будут автоматически сохраненыlocalStorage
. Вы всегда играете с реальным объектом, поэтому вы можете делать такие вещи:И каждый новый объект внутри отслеживаемого объекта будет автоматически отслеживаться.
Очень большой недостаток: это зависит от того,
Object.observe()
поэтому он имеет очень ограниченную поддержку браузера. И не похоже, что это будет в ближайшее время для Firefox или Edge.источник
Вы не можете сохранить значение ключа без формата строки .
LocalStorage поддерживает только формат String для ключа / значения.
Вот почему вы должны преобразовать ваши данные в строку, независимо от того, какой это массив или объект. .
Чтобы сохранить данные в localStorage, в первую очередь зашифруйте их, используя метод JSON.stringify () .
Затем, когда вы хотите получить данные, вам нужно снова проанализировать строку для объекта.
Надеюсь, поможет.
источник
Чтобы сохранить объект, вы можете сделать буквы, которые вы можете использовать, чтобы получить объект из строки в объект (может не иметь смысла). Например
Эта техника вызовет некоторые сбои, если вы используете букву, которую вы использовали для разделения объекта, и она также очень экспериментальная.
источник
Я нашел способ заставить его работать с объектами, которые имеют циклические ссылки.
Давайте сделаем объект с циклическими ссылками.
Мы не можем сделать
JSON.stringify
здесь, из-за циклических ссылок.LOCALSTORAGE.CYCLICJSON
имеет.stringify
и так.parse
же, как обычноJSON
, но работает с объектами с круговыми ссылками. («Работает» означает parse (stringify (obj)) и obj глубоко равны И имеют идентичные наборы «внутренних равенств»)Но мы можем просто использовать ярлыки:
Тогда
recovered
будет "то же самое" для obj, в следующем смысле:Вот реализация
LOCALSTORAGE
источник
localStorage.setItem ('user', JSON.stringify (user));
Затем, чтобы извлечь его из магазина и снова преобразовать в объект:
var user = JSON.parse (localStorage.getItem ('user'));
Если нам нужно удалить все записи магазина, мы можем просто сделать:
localStorage.clear ();
источник