Chciałbym przechowywać obiekt JavaScript w HTML5 localStorage
, ale mój obiekt najwyraźniej jest konwertowany na ciąg znaków.
Mogę przechowywać i pobierać prymitywne typy i tablice JavaScript za pomocą localStorage
, ale obiekty nie działają. Powinni?
Oto mój kod:
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);
Dane wyjściowe konsoli to
typeof testObject: object
testObject properties:
one: 1
two: 2
three: 3
typeof retrievedObject: string
Value of retrievedObject: [object Object]
Wydaje mi się, że ta setItem
metoda konwertuje dane wejściowe na ciąg znaków przed ich zapisaniem.
Widzę to zachowanie w Safari, Chrome i Firefox, więc zakładam, że nie rozumiem specyfikacji HTML5 Web Storage , a nie błędu lub ograniczenia specyficznego dla przeglądarki.
Próbowałem zrozumieć algorytm ustrukturyzowanego klonowania opisany w http://www.w3.org/TR/html5/infrastructure.html . Nie do końca rozumiem, co to mówi, ale może mój problem dotyczy tego, że właściwości mojego obiektu nie są policzalne (???)
Czy istnieje łatwe obejście?
Aktualizacja: W3C ostatecznie zmieniło zdanie na temat specyfikacji klonowania strukturalnego i zdecydowało się zmienić specyfikację, aby pasowała do implementacji. Zobacz https://www.w3.org/Bugs/Public/show_bug.cgi?id=12111 . To pytanie nie jest już w 100% prawidłowe, ale odpowiedzi mogą być interesujące.
źródło
Odpowiedzi:
Patrząc ponownie na dokumentację Apple , Mozilla i Mozilla , wydaje się, że funkcjonalność jest ograniczona do obsługi tylko par ciągów klucz / wartość.
Obejściem może być sprecyzowanie obiektu przed zapisaniem go, a następnie jego przeanalizowanie po odzyskaniu:
źródło
JSON.stringify()
rozwija obiekt, do którego się odwołuje, do pełnej „treści” (niejawnie zeszeregowanej) w obiekcie, który tworzymy. Zobacz: stackoverflow.com/a/12659424/2044940Niewielka poprawa w wariancie :
Z powodu oceny zwarcia ,
getObject()
będzie natychmiast wrócićnull
, jeślikey
nie ma w magazynie. Nie wyrzuci równieżSyntaxError
wyjątku, jeślivalue
jest""
(pusty ciąg;JSON.parse()
nie może tego obsłużyć).źródło
var userObject = { userId: 24, name: 'Jack Bauer' };
I ustawić je, alocalStorage.setObject('user', userObject);
następnie odzyskać z pamięci.userObject = localStorage.getObject('user');
Możesz nawet zapisać tablicę obiektów, jeśli chcesz.key
nie jest w pamięci lokalnej,window.localStorage.getItem(key)
powrotynull
- to jednak nie rzucać się „nielegalnego dostępu” wyjątek - iJSON.parse(null)
powracanull
jak dobrze - to jednak nie wyjątek albo, ani w Chromium 21 ani za ES 5.1 sekcji 15.12.2 , ponieważString(null) === "null"
, które mogą być interpretowane jako literał JSON .""
(pusty ciąg). Ponieważ konwertuje typ nafalse
iJSON.parse("")
, co spowodowałobySyntaxError
wyjątek, nie jest wywoływany.Przydatne może być rozszerzenie obiektu Storage za pomocą tych przydatnych metod:
W ten sposób otrzymujesz funkcjonalność, którą naprawdę chciałeś, mimo że pod API obsługuje tylko łańcuchy.
źródło
localStorage.setObject
.getObject()
to zgłoszenieSyntaxError
wyjątku, jeśli przechowywana jest wartość""
, ponieważJSON.parse()
nie może tego obsłużyć. Zobacz moją edycję odpowiedzi Gurii, aby uzyskać szczegółowe informacje.Rozszerzenie obiektu Storage to niesamowite rozwiązanie. Dla mojego interfejsu API utworzyłem fasadę dla localStorage, a następnie sprawdzam, czy jest to obiekt, czy nie podczas ustawiania i pobierania.
źródło
data.set('username': 'ifedi', 'fullname': { firstname: 'Ifedi', lastname: 'Okonkwo'});
?Stringify nie rozwiązuje wszystkich problemów
Wygląda na to, że odpowiedzi tutaj nie obejmują wszystkich typów możliwych w JavaScript, więc oto kilka krótkich przykładów, jak poprawnie sobie z nimi poradzić:
Nie polecam przechowywania funkcji, ponieważ
eval()
zło może prowadzić do problemów związanych z bezpieczeństwem, optymalizacją i debugowaniem. Zasadniczoeval()
nigdy nie należy go używać w kodzie JavaScript.Członkowie prywatni
Problem z używaniem
JSON.stringify()
do przechowywania obiektów polega na tym, że ta funkcja nie może serializować prywatnych członków. Ten problem można rozwiązać, zastępując.toString()
metodę (która jest wywoływana niejawnie podczas przechowywania danych w pamięci internetowej):Referencje kołowe
Innym problemem, z którym
stringify
nie można sobie poradzić, są odwołania cykliczne:W tym przykładzie
JSON.stringify()
wyrzuciTypeError
„Konwertowanie okrągłej struktury na JSON” . Jeśli powinno być obsługiwane przechowywanie odniesień cyklicznych, można użyć drugiego parametruJSON.stringify()
:Jednak znalezienie skutecznego rozwiązania do przechowywania cyklicznych odniesień w dużej mierze zależy od zadań, które należy rozwiązać, a przywrócenie takich danych nie jest również trywialne.
Istnieją już pytania dotyczące SO dotyczące tego problemu: Stringify (konwersja do JSON) obiekt JavaScript z referencją cykliczną
źródło
Istnieje świetna biblioteka, która zawiera wiele rozwiązań, więc obsługuje nawet starsze przeglądarki o nazwie jStorage
Możesz ustawić obiekt
I łatwo to odzyskać
źródło
Teoretycznie możliwe jest przechowywanie obiektów z funkcjami:
Jednak serializacja / deserializacja funkcji jest zawodna, ponieważ zależy od implementacji .
źródło
c.f[k] = escape(a[k]);
z Unicode bezpiecznyc.f[k] = encodeURIComponent(a[k]);
ieval('b.' + k + ' = ' + unescape(data.f[k]));
zb[k] = eval("(" + decodeURIComponent(data.f[k]) + ")");
. Nawiasy są wymagane, ponieważ twoja funkcja, jeśli zostanie poprawnie zserializowana, prawdopodobnie będzie anonimowa, co nie jest tak, jak jest poprawne / Instrukcja / (więceval()
) wSyntaxError
przeciwnym razie zgłasza wyjątek).typeof
jest operatorem , nie pisz go tak, jakby to była funkcja. Wymieńtypeof(a[k])
siętypeof a[k]
.for
-in
nie został przefiltrowany dla własnych właściwości. 3. Styl kodu, w tym odniesienia, był niespójny.the use and placement of white space, line terminators, and semicolons within the representation String is implementation-dependent.
, że nie widzę żadnych różnic funkcjonalnych.Note *in particular* that …
. Ale specyfikacja wartości zwracanej zaczyna się odAn implementation-dependent representation of the function is returned. This representation has the syntax of a FunctionDeclaration.
Wartość zwracana może byćfunction foo () {}
- przy założeniu zgodnej implementacji.Doszedłem do tego postu po trafieniu na inny post, który został zamknięty jako duplikat tego - zatytułowany „jak przechowywać tablicę w localstorage?”. Co jest w porządku, z wyjątkiem tego, że żaden wątek nie zapewnia pełnej odpowiedzi na temat tego, w jaki sposób można utrzymywać tablicę w localStorage - udało mi się jednak opracować rozwiązanie na podstawie informacji zawartych w obu wątkach.
Więc jeśli ktokolwiek chce móc pchać / pop / przesuwać elementy w tablicy i chce, aby tablica była przechowywana w localStorage lub faktycznie sessionStorage, proszę:
przykład użycia - przechowywanie prostych ciągów w tablicy localStorage:
przykład użycia - przechowywanie obiektów w tablicy sessionStorage:
popularne metody manipulowania tablicami:
źródło
Zalecamy korzystanie z biblioteki abstrakcji dla wielu omawianych tu funkcji, a także dla lepszej kompatybilności. Wiele opcji:
źródło
Za pomocą localDataStorage można w przejrzysty sposób przechowywać typy danych javascript (Array, Boolean, Date, Float, Integer, String i Object). Zapewnia również lekkie zaciemnianie danych, automatycznie kompresuje ciągi, ułatwia zapytania według klucza (nazwy), a także zapytania według (klucza) wartości, a także pomaga wymuszać dzielone dzielone miejsce do magazynowania w tej samej domenie przez prefiksowanie kluczy.
[OŚWIADCZENIE] Jestem autorem narzędzia [/ OŚWIADCZENIE]
Przykłady:
Jak widać, prymitywne wartości są przestrzegane.
źródło
Inną opcją byłoby użycie istniejącej wtyczki.
Na przykład persisto to projekt typu open source, który zapewnia łatwy interfejs do localStorage / sessionStorage i automatyzuje trwałość pól formularzy (wprowadzania, przycisków opcji i pól wyboru).
(Uwaga: Jestem autorem).
źródło
localStroage
; exp:var lsh = new localStorageHelper(); lsh.setItem('bob', 'bill');
Obejmuje również zdarzenia.Możesz użyć ejson do przechowywania obiektów jako ciągów.
Oto moje opakowanie localStorage za pomocą ejson
https://github.com/UziTech/storage.js
Dodałem kilka rodzajów do mojego opakowania, w tym wyrażenia regularne i funkcje
źródło
Zrobiłem kolejne minimalistyczne opakowanie z tylko 20 liniami kodu, aby umożliwić korzystanie z niego tak, jak powinno:
https://github.com/zevero/simpleWebstorage
źródło
Dla użytkowników maszynopisu, którzy chcą ustawić i uzyskać właściwości pisania:
Przykładowe użycie :
źródło
https://github.com/adrianmay/rhaboo jest warstwą cukru localStorage, która pozwala pisać takie rzeczy:
Nie używa JSON.stringify / parsować, ponieważ byłoby to niedokładne i wolne dla dużych obiektów. Zamiast tego każda wartość terminala ma własny wpis localStorage.
Prawdopodobnie można się domyślić, że mógłbym mieć coś wspólnego z rababem.
źródło
Oto rozbudowana wersja kodu opublikowana przez @danott
Zaimplementuje również wartość usuwania z pamięci lokalnej i pokaże, jak dodać warstwę Gettera i Settera zamiast
localstorage.setItem(preview, true)
Możesz pisać
config.preview = true
Okej, proszę bardzo:
Możesz usunąć część aliasów
.bind(...)
. Jednak po prostu to włożyłem, ponieważ naprawdę dobrze o tym wiedzieć. Zajęło mi godziny, aby dowiedzieć się, dlaczego prostyget = localStorage.getItem;
nie działaźródło
Zrobiłem coś, co nie psuje istniejących obiektów Storage, ale tworzy opakowanie, dzięki czemu możesz robić, co chcesz. Rezultatem jest normalny obiekt, bez metod, z dostępem jak każdy obiekt.
Rzecz, którą zrobiłem.
Jeśli chcesz, aby 1
localStorage
właściwość była magiczna:Jeśli potrzebujesz kilku:
Wszystko, co zrobisz
prop
, lub przedmioty w środkustorage
zostaną automatycznie zapisanelocalStorage
. Zawsze bawisz się prawdziwym przedmiotem, więc możesz robić takie rzeczy:I każdy nowy przedmiot w środku śledzonym obiekcie będzie automatycznie śledzony.
Bardzo duży minus: zależy,
Object.observe()
więc ma bardzo ograniczone wsparcie przeglądarki. I nie wygląda na to, że wkrótce pojawi się w przeglądarce Firefox lub Edge.źródło
Nie można zapisać wartości klucza bez String Format.
Lokalny magazyn obsługuje tylko format ciągu dla klucza / wartości.
Dlatego należy przekonwertować dane na ciąg cokolwiek to jest Array lub obiektu .
Aby przechowywać dane w localStorage, należy przede wszystkim skreślić je za pomocą metody JSON.stringify () .
Następnie, gdy chcesz odzyskać dane, musisz ponownie przeanalizować ciąg znaków do obiektu.
Mam nadzieję, że to pomoże.
źródło
Aby przechowywać obiekt, możesz utworzyć litery, za pomocą których można przenieść obiekt z łańcucha do obiektu (może to nie mieć sensu). Na przykład
Ta technika spowoduje pewne usterki, jeśli użyjesz litery, której użyłeś do podzielenia obiektu, a także jest bardzo eksperymentalna.
źródło
Znalazłem sposób, aby działał z obiektami, które mają cykliczne odwołania.
Stwórzmy obiekt z cyklicznymi referencjami.
Nie możemy tego zrobić
JSON.stringify
z powodu okólników.LOCALSTORAGE.CYCLICJSON
ma.stringify
i.parse
tak jak normalnieJSON
, ale działa z obiektami z referencjami kołowymi. („Works” oznacza parsować (stringify (obj)) i obj są głęboko równe ORAZ mają identyczne zestawy „wewnętrznych równości”)Ale możemy po prostu użyć skrótów:
Wtedy
recovered
będzie „taki sam” dla obj, w następującym znaczeniu:Oto wdrożenie
LOCALSTORAGE
źródło
localStorage.setItem („użytkownik”, JSON.stringify (użytkownik));
Następnie, aby pobrać go ze sklepu i ponownie przekonwertować na obiekt:
var user = JSON.parse (localStorage.getItem ('użytkownik'));
Jeśli musimy usunąć wszystkie wpisy ze sklepu, możemy po prostu zrobić:
localStorage.clear ();
źródło