질문자 :Kristopher Johnson
localStorage
JavaScript 개체를 저장하고 싶지만 내 개체가 문자열로 변환되고 있는 것 같습니다.
localStorage
사용하여 기본 JavaScript 유형과 배열을 저장하고 검색할 수 있지만 객체가 작동하지 않는 것 같습니다. 그들은해야합니까?
내 코드는 다음과 같습니다.
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 Web Storage 사양을 잘못 이해한 것으로 가정합니다.
http://www.w3.org/TR/html5/infrastructure.html 에 설명된 구조화된 복제 알고리즘을 이해하려고 했습니다. 나는 그것이 말하는 것을 완전히 이해하지 못하지만 아마도 내 문제는 열거 할 수없는 내 개체의 속성과 관련이있을 수 있습니다 (???)
쉬운 해결 방법이 있습니까?
업데이트: W3C는 결국 구조적 클론 사양에 대한 마음을 바꾸고 구현과 일치하도록 사양을 변경하기로 결정했습니다. https://www.w3.org/Bugs/Public/show_bug.cgi?id=12111 을 참조하십시오. 따라서 이 질문은 더 이상 100% 유효하지 않지만 답변은 여전히 흥미로울 수 있습니다.
Apple , Mozilla 및 Mozilla 다시 문서를 보면 기능이 문자열 키/값 쌍만 처리하도록 제한되어 있는 것 같습니다.
해결 방법은 객체를 저장하기 전에 문자열화 하고 나중에 검색할 때 구문 분석하는 것입니다.
var testObject = { 'one': 1, 'two': 2, 'three': 3 }; // Put the object into storage localStorage.setItem('testObject', JSON.stringify(testObject)); // Retrieve the object from storage var retrievedObject = localStorage.getItem('testObject'); console.log('retrievedObject: ', JSON.parse(retrievedObject));
Christian C. Salvadó변형 에 대한 사소한 개선 사항:
Storage.prototype.setObject = function(key, value) { this.setItem(key, JSON.stringify(value)); } Storage.prototype.getObject = function(key) { var value = this.getItem(key); return value && JSON.parse(value); }
단락 평가로 인해 key
가 저장소에 없으면 getObject()
는 즉시 null
반환합니다. value
이 ""
SyntaxError
예외가 발생하지 않습니다(빈 문자열, JSON.parse()
가 이를 처리할 수 없음).
Guria다음과 같은 편리한 방법으로 Storage 객체를 확장하는 것이 유용할 수 있습니다.
Storage.prototype.setObject = function(key, value) { this.setItem(key, JSON.stringify(value)); } Storage.prototype.getObject = function(key) { return JSON.parse(this.getItem(key)); }
이렇게 하면 API 아래에서 문자열만 지원하더라도 실제로 원하는 기능을 얻을 수 있습니다.
Justin VoskuhlStorage 개체를 확장하는 것은 멋진 솔루션입니다. 내 API의 경우 localStorage에 대한 파사드를 만든 다음 설정 및 가져오는 동안 개체인지 확인합니다.
var data = { set: function(key, value) { if (!key || !value) {return;} if (typeof value === "object") { value = JSON.stringify(value); } localStorage.setItem(key, value); }, get: function(key) { var value = localStorage.getItem(key); if (!value) {return;} // assume it is an object that has been stringified if (value[0] === "{") { value = JSON.parse(value); } return value; } }
Alex GrandeStringify가 모든 문제를 해결하는 것은 아닙니다.
여기에 있는 답변이 JavaScript에서 가능한 모든 유형을 다루지는 않는 것 같으므로 다음은 올바르게 처리하는 방법에 대한 몇 가지 간단한 예입니다.
//Objects and Arrays: var obj = {key: "value"}; localStorage.object = JSON.stringify(obj); //Will ignore private members obj = JSON.parse(localStorage.object); //Boolean: var bool = false; localStorage.bool = bool; bool = (localStorage.bool === "true"); //Numbers: var num = 42; localStorage.num = num; num = +localStorage.num; //short for "num = parseFloat(localStorage.num);" //Dates: var date = Date.now(); localStorage.date = date; date = new Date(parseInt(localStorage.date)); //Regular expressions: var regex = /^No\.[\d]*$/i; //usage example: "No.42".match(regex); localStorage.regex = regex; var components = localStorage.regex.match("^/(.*)/([az]*)$"); regex = new RegExp(components[1], components[2]); //Functions (not recommended): function func(){} localStorage.func = func; eval( localStorage.func ); //recreates the function with the name "func"
eval()
은 보안, 최적화 및 디버깅과 관련된 문제를 일으킬 수 있기 때문에 함수를 저장 하지 않는 것이 좋습니다. 일반적으로 eval()
은 JavaScript 코드에서 사용하면 안 됩니다.
비공개 회원
JSON.stringify()
를 사용할 때의 문제는 이 함수가 private 멤버를 직렬화할 수 없다는 것입니다. .toString()
메서드(웹 저장소에 데이터를 저장할 때 암시적으로 호출됨)를 덮어써서 해결할 수 있습니다.
//Object with private and public members: function MyClass(privateContent, publicContent){ var privateMember = privateContent || "defaultPrivateValue"; this.publicMember = publicContent || "defaultPublicValue"; this.toString = function(){ return '{"private": "' + privateMember + '", "public": "' + this.publicMember + '"}'; }; } MyClass.fromString = function(serialisedString){ var properties = JSON.parse(serialisedString || "{}"); return new MyClass( properties.private, properties.public ); }; //Storing: var obj = new MyClass("invisible", "visible"); localStorage.object = obj; //Loading: obj = MyClass.fromString(localStorage.object);
순환 참조
stringify
가 처리할 수 없는 또 다른 문제는 순환 참조입니다.
var obj = {}; obj["circular"] = obj; localStorage.object = JSON.stringify(obj); //Fails
이 예에서 JSON.stringify()
는 TypeError
"Converting circle structure to JSON" 을 발생 시킵니다. 순환 참조 저장이 지원되어야 하는 경우 JSON.stringify()
의 두 번째 매개변수를 사용할 수 있습니다.
var obj = {id: 1, sub: {}}; obj.sub["circular"] = obj; localStorage.object = JSON.stringify( obj, function( key, value) { if( key == 'circular') { return "$ref"+value.id+"$"; } else { return value; } });
그러나 순환 참조를 저장하기 위한 효율적인 솔루션을 찾는 것은 해결해야 하는 작업에 따라 크게 달라지며 이러한 데이터를 복원하는 것도 쉬운 일이 아닙니다.
이 문제를 다루는 SO에 대한 몇 가지 질문이 이미 있습니다. 순환 참조가 있는 JavaScript 객체 Stringify(JSON으로 변환)
majajStorage 라는 오래된 브라우저도 지원하도록 많은 솔루션을 포함하는 훌륭한 라이브러리가 있습니다.
개체를 설정할 수 있습니다
$.jStorage.set(key, value)
그리고 쉽게 되찾으세요.
value = $.jStorage.get(key) value = $.jStorage.get(key, "default value")
JProgrammer이론적으로 다음과 같은 기능으로 객체를 저장할 수 있습니다.
function store (a) { var c = {f: {}, d: {}}; for (var k in a) { if (a.hasOwnProperty(k) && typeof a[k] === 'function') { cf[k] = encodeURIComponent(a[k]); } } cd = a; var data = JSON.stringify(c); window.localStorage.setItem('CODE', data); } function restore () { var data = window.localStorage.getItem('CODE'); data = JSON.parse(data); var b = data.d; for (var k in data.f) { if (data.f.hasOwnProperty(k)) { b[k] = eval("(" + decodeURIComponent(data.f[k]) + ")"); } } return b; }
그러나 함수 직렬화/역직렬화 는 구현 종속적 이므로 신뢰할 수 없습니다.
aster_x나는 'localstorage에 배열을 저장하는 방법?'이라는 제목의 이 게시물의 복제본으로 폐쇄된 다른 게시물을 보고 이 게시물에 도착했습니다. 두 스레드 모두 실제로 localStorage에서 배열을 유지 관리하는 방법에 대한 완전한 답변을 제공하지 않는다는 점을 제외하고는 괜찮습니다. 그러나 두 스레드에 포함된 정보를 기반으로 솔루션을 만들 수 있었습니다.
따라서 다른 사람이 배열 내에서 항목을 푸시/팝/시프트할 수 있기를 원하고 해당 배열이 localStorage 또는 실제로 sessionStorage에 저장되기를 원하는 경우 여기로 이동합니다.
Storage.prototype.getArray = function(arrayName) { var thisArray = []; var fetchArrayObject = this.getItem(arrayName); if (typeof fetchArrayObject !== 'undefined') { if (fetchArrayObject !== null) { thisArray = JSON.parse(fetchArrayObject); } } return thisArray; } Storage.prototype.pushArrayItem = function(arrayName,arrayItem) { var existingArray = this.getArray(arrayName); existingArray.push(arrayItem); this.setItem(arrayName,JSON.stringify(existingArray)); } Storage.prototype.popArrayItem = function(arrayName) { var arrayItem = {}; var existingArray = this.getArray(arrayName); if (existingArray.length > 0) { arrayItem = existingArray.pop(); this.setItem(arrayName,JSON.stringify(existingArray)); } return arrayItem; } Storage.prototype.shiftArrayItem = function(arrayName) { var arrayItem = {}; var existingArray = this.getArray(arrayName); if (existingArray.length > 0) { arrayItem = existingArray.shift(); this.setItem(arrayName,JSON.stringify(existingArray)); } return arrayItem; } Storage.prototype.unshiftArrayItem = function(arrayName,arrayItem) { var existingArray = this.getArray(arrayName); existingArray.unshift(arrayItem); this.setItem(arrayName,JSON.stringify(existingArray)); } Storage.prototype.deleteArray = function(arrayName) { this.removeItem(arrayName); }
사용 예 - localStorage 배열에 간단한 문자열 저장:
localStorage.pushArrayItem('myArray','item one'); localStorage.pushArrayItem('myArray','item two');
사용 예 - sessionStorage 배열에 객체 저장:
var item1 = {}; item1.name = 'fred'; item1.age = 48; sessionStorage.pushArrayItem('myArray',item1); var item2 = {}; item2.name = 'dave'; item2.age = 22; sessionStorage.pushArrayItem('myArray',item2);
배열을 조작하는 일반적인 방법:
.pushArrayItem(arrayName,arrayItem); -> adds an element onto end of named array .unshiftArrayItem(arrayName,arrayItem); -> adds an element onto front of named array .popArrayItem(arrayName); -> removes & returns last array element .shiftArrayItem(arrayName); -> removes & returns first array element .getArray(arrayName); -> returns entire array .deleteArray(arrayName); -> removes entire array from storage
Andy Lorenz여기에 설명된 많은 기능과 더 나은 호환성을 위해 추상화 라이브러리를 사용하는 것이 좋습니다. 다양한 옵션:
doublejoshlocalDataStorage 를 사용하여 자바스크립트 데이터 유형(배열, 부울, 날짜, 부동 소수점, 정수, 문자열 및 개체)을 투명하게 저장할 수 있습니다. 또한 경량 데이터 난독화를 제공하고, 문자열을 자동으로 압축하고, 키(이름) 및 값(키) 쿼리를 용이하게 하고, 접두사 키를 사용하여 동일한 도메인 내에서 분할된 공유 스토리지를 시행하는 데 도움이 됩니다.
[DISCLAIMER] 저는 유틸리티의 작성자입니다. [/DISCLAIMER]
예:
localDataStorage.set( 'key1', 'Belgian' ) localDataStorage.set( 'key2', 1200.0047 ) localDataStorage.set( 'key3', true ) localDataStorage.set( 'key4', { 'RSK' : [1,'3',5,'7',9] } ) localDataStorage.set( 'key5', null ) localDataStorage.get( 'key1' ) --> 'Belgian' localDataStorage.get( 'key2' ) --> 1200.0047 localDataStorage.get( 'key3' ) --> true localDataStorage.get( 'key4' ) --> Object {RSK: Array(5)} localDataStorage.get( 'key5' ) --> null
보시다시피 원시 값이 존중됩니다.
Macejson 을 사용하여 객체를 문자열로 저장할 수 있습니다.
EJSON은 더 많은 유형을 지원하기 위한 JSON의 확장입니다. 모든 JSON 안전 유형과 다음을 지원합니다.
모든 EJSON 직렬화도 유효한 JSON입니다. 예를 들어 날짜와 바이너리 버퍼가 있는 객체는 EJSON에서 다음과 같이 직렬화됩니다.
{ "d": {"$date": 1358205756553}, "b": {"$binary": "c3VyZS4="} }
다음은 ejson을 사용하는 내 localStorage 래퍼입니다.
https://github.com/UziTech/storage.js
정규 표현식과 함수를 포함하여 래퍼에 몇 가지 유형을 추가했습니다.
Tony Brix또 다른 옵션은 기존 플러그인을 사용하는 것입니다.
예를 들어 persistenceo 는 localStorage/sessionStorage에 대한 쉬운 인터페이스를 제공하고 양식 필드(입력, 라디오 버튼 및 확인란)에 대한 지속성을 자동화하는 오픈 소스 프로젝트입니다.
(면책 조항 : 나는 저자입니다.)
mar10문자열 형식 없이 키 값을 저장할 수 없습니다.
LocalStorage 는 키/값에 대한 문자열 형식만 지원합니다.
그렇기 때문에 데이터를 Array 또는 Object 무엇이든 문자열로 변환해야 합니다.
localStorage에 데이터를 저장하려면 먼저 JSON.stringify() 메서드를 사용하여 문자열화합니다.
var myObj = [{name:"test", time:"Date 2017-02-03T08:38:04.449Z"}]; localStorage.setItem('item', JSON.stringify(myObj));
그런 다음 데이터를 검색하려면 String을 Object로 다시 구문 분석해야 합니다.
var getObj = JSON.parse(localStorage.getItem('item'));
도움이 되기를 바랍니다.
Moshiur Rahman유형 속성을 설정하고 가져오려는 Typescript 사용자의 경우:
/** * Silly wrapper to be able to type the storage keys */ export class TypedStorage<T> { public removeItem(key: keyof T): void { localStorage.removeItem(key); } public getItem<K extends keyof T>(key: K): T[K] | null { const data: string | null = localStorage.getItem(key); return JSON.parse(data); } public setItem<K extends keyof T>(key: K, value: T[K]): void { const data: string = JSON.stringify(value); localStorage.setItem(key, data); } }
사용 예 :
// write an interface for the storage interface MyStore { age: number, name: string, address: {city:string} } const storage: TypedStorage<MyStore> = new TypedStorage<MyStore>(); storage.setItem("wrong key", ""); // error unknown key storage.setItem("age", "hello"); // error, age should be number storage.setItem("address", {city:"Here"}); // ok const address: {city:string} = storage.getItem("address");
Flavien Volkenhttps://github.com/adrianmay/rhaboo 는 다음과 같이 작성할 수 있는 localStorage 설탕 레이어입니다.
var store = Rhaboo.persistent('Some name'); store.write('count', store.count ? store.count+1 : 1); store.write('somethingfancy', { one: ['man', 'went'], 2: 'mow', went: [ 2, { mow: ['a', 'meadow' ] }, {} ] }); store.somethingfancy.went[1].mow.write(1, 'lawn');
큰 개체에서는 정확하지 않고 느리기 때문에 JSON.stringify/parse를 사용하지 않습니다. 대신 각 터미널 값에는 자체 localStorage 항목이 있습니다.
내가 rhaboo와 관련이 있을지도 모른다고 추측할 수 있습니다.
Adrian May다음과 같이 사용할 수 있도록 20줄의 코드로 또 다른 최소한의 래퍼를 만들었습니다.
localStorage.set('myKey',{a:[1,2,5], b: 'ok'}); localStorage.has('myKey'); // --> true localStorage.get('myKey'); // --> {a:[1,2,5], b: 'ok'} localStorage.keys(); // --> ['myKey'] localStorage.remove('myKey');
https://github.com/zevero/simpleWebstorage
zevero@danott가 게시한 코드의 일부 확장 버전은 다음과 같습니다.
또한 localstorage에서 삭제 값을 구현하고 Getter 및 Setter 레이어를 추가하는 방법을 보여줍니다.
localstorage.setItem(preview, true)
당신은 쓸 수 있습니다
config.preview = true
좋아 여기 갔다:
var PT=Storage.prototype if (typeof PT._setItem >='u') PT._setItem = PT.setItem; PT.setItem = function(key, value) { if (typeof value >='u')//..ndefined this.removeItem(key) else this._setItem(key, JSON.stringify(value)); } if (typeof PT._getItem >='u') PT._getItem = PT.getItem; PT.getItem = function(key) { var ItemData = this._getItem(key) try { return JSON.parse(ItemData); } catch(e) { return ItemData; } } // Aliases for localStorage.set/getItem get = localStorage.getItem.bind(localStorage) set = localStorage.setItem.bind(localStorage) // Create ConfigWrapperObject var config = {} // Helper to create getter & setter function configCreate(PropToAdd){ Object.defineProperty( config, PropToAdd, { get: function () { return ( get(PropToAdd) ) }, set: function (val) { set(PropToAdd, val ) } }) } //------------------------------ // Usage Part // Create properties configCreate('preview') configCreate('notification') //... // Config Data transfer //set config.preview = true //get config.preview // delete config.preview = undefined
.bind(...)
사용하여 aliases 부분을 제거할 수 있습니다. 그러나 나는 이것에 대해 정말로 알고 있기 때문에 그것을 넣었습니다. 간단한 get = localStorage.getItem;
일하지마
Nadu기존 Storage 객체를 망가뜨리지 않고 래퍼(wrapper)를 생성하여 원하는 것을 할 수 있도록 만들었습니다. 결과는 다른 개체와 마찬가지로 액세스 권한이 있는 메서드가 없는 일반 개체입니다.
내가 만든 것.
1개의 localStorage
속성을 마법처럼 사용하려면:
var prop = ObjectStorage(localStorage, 'prop');
여러 개가 필요한 경우:
var storage = ObjectStorage(localStorage, ['prop', 'more', 'props']);
prop
모든 작업 storage
내부 의 객체는 자동으로 localStorage
저장됩니다. 항상 실제 개체를 가지고 놀고 있으므로 다음과 같은 작업을 수행할 수 있습니다.
storage.data.list.push('more data'); storage.another.list.splice(1, 2, {another: 'object'});
그리고 추적된 개체 내부 의 모든 새 개체는 자동으로 추적됩니다.
매우 큰 단점: Object.observe()
에 의존하므로 브라우저 지원이 매우 제한적입니다. 그리고 조만간 파이어폭스나 엣지용으로 나올 것 같지도 않다.
Rudie순환 참조가 있는 개체와 함께 작동하도록 하는 방법을 찾았습니다.
순환 참조로 객체를 만들어 봅시다.
obj = { L: { L: { v: 'lorem' }, R: { v: 'ipsum' } }, R: { L: { v: 'dolor' }, R: { L: { v: 'sit' }, R: { v: 'amet' } } } } obj.RLuncle = obj.L; obj.RRuncle = obj.L; obj.RRLuncle = obj.RL; obj.RRRuncle = obj.RL; obj.LLuncle = obj.R; obj.LRuncle = obj.R;
순환 참조 때문에 여기서는 JSON.stringify
수행할 수 없습니다.
LOCALSTORAGE.CYCLICJSON
에는 JSON
과 마찬가지로 .stringify
및 .parse
있지만 순환 참조가 있는 개체와 함께 작동합니다. ( parse(stringify(obj)) 와 obj 는 완전히 동일하고 동일한 '내부 동등성' 세트를 가짐을 의미하는 "작동")
그러나 바로 가기를 사용할 수 있습니다.
LOCALSTORAGE.setObject('latinUncles', obj) recovered = LOCALSTORAGE.getObject('latinUncles')
그런 다음 recovered
것은 다음과 같은 의미에서 obj와 "동일"합니다.
[ obj.LLv === recovered.LLv, obj.LRv === recovered.LRv, obj.RLv === recovered.RLv, obj.RRLv === recovered.RRLv, obj.RRRv === recovered.RRRv, obj.RLuncle === obj.L, obj.RRuncle === obj.L, obj.RRLuncle === obj.RL, obj.RRRuncle === obj.RL, obj.LLuncle === obj.R, obj.LRuncle === obj.R, recovered.RLuncle === recovered.L, recovered.RRuncle === recovered.L, recovered.RRLuncle === recovered.RL, recovered.RRRuncle === recovered.RL, recovered.LLuncle === recovered.R, recovered.LRuncle === recovered.R ]
LOCALSTORAGE
의 구현입니다.
LOCALSTORAGE = (function(){ "use strict"; var ignore = [Boolean, Date, Number, RegExp, String]; function primitive(item){ if (typeof item === 'object'){ if (item === null) { return true; } for (var i=0; i<ignore.length; i++){ if (item instanceof ignore[i]) { return true; } } return false; } else { return true; } } function infant(value){ return Array.isArray(value) ? [] : {}; } function decycleIntoForest(object, replacer) { if (typeof replacer !== 'function'){ replacer = function(x){ return x; } } object = replacer(object); if (primitive(object)) return object; var objects = [object]; var forest = [infant(object)]; var bucket = new WeakMap(); // bucket = inverse of objects bucket.set(object, 0); function addToBucket(obj){ var result = objects.length; objects.push(obj); bucket.set(obj, result); return result; } function isInBucket(obj){ return bucket.has(obj); } function processNode(source, target){ Object.keys(source).forEach(function(key){ var value = replacer(source[key]); if (primitive(value)){ target[key] = {value: value}; } else { var ptr; if (isInBucket(value)){ ptr = bucket.get(value); } else { ptr = addToBucket(value); var newTree = infant(value); forest.push(newTree); processNode(value, newTree); } target[key] = {pointer: ptr}; } }); } processNode(object, forest[0]); return forest; }; function deForestIntoCycle(forest) { var objects = []; var objectRequested = []; var todo = []; function processTree(idx) { if (idx in objects) return objects[idx]; if (objectRequested[idx]) return null; objectRequested[idx] = true; var tree = forest[idx]; var node = Array.isArray(tree) ? [] : {}; for (var key in tree) { var o = tree[key]; if ('pointer' in o) { var ptr = o.pointer; var value = processTree(ptr); if (value === null) { todo.push({ node: node, key: key, idx: ptr }); } else { node[key] = value; } } else { if ('value' in o) { node[key] = o.value; } else { throw new Error('unexpected') } } } objects[idx] = node; return node; } var result = processTree(0); for (var i = 0; i < todo.length; i++) { var item = todo[i]; item.node[item.key] = objects[item.idx]; } return result; }; var console = { log: function(x){ var the = document.getElementById('the'); the.textContent = the.textContent + '\n' + x; }, delimiter: function(){ var the = document.getElementById('the'); the.textContent = the.textContent + '\n*******************************************'; } } function logCyclicObjectToConsole(root) { var cycleFree = decycleIntoForest(root); var shown = cycleFree.map(function(tree, idx) { return false; }); var indentIncrement = 4; function showItem(nodeSlot, indent, label) { var leadingSpaces = ' '.repeat(indent); var leadingSpacesPlus = ' '.repeat(indent + indentIncrement); if (shown[nodeSlot]) { console.log(leadingSpaces + label + ' ... see above (object #' + nodeSlot + ')'); } else { console.log(leadingSpaces + label + ' object#' + nodeSlot); var tree = cycleFree[nodeSlot]; shown[nodeSlot] = true; Object.keys(tree).forEach(function(key) { var entry = tree[key]; if ('value' in entry) { console.log(leadingSpacesPlus + key + ": " + entry.value); } else { if ('pointer' in entry) { showItem(entry.pointer, indent + indentIncrement, key); } } }); } } console.delimiter(); showItem(0, 0, 'root'); }; function stringify(obj){ return JSON.stringify(decycleIntoForest(obj)); } function parse(str){ return deForestIntoCycle(JSON.parse(str)); } var CYCLICJSON = { decycleIntoForest: decycleIntoForest, deForestIntoCycle : deForestIntoCycle, logCyclicObjectToConsole: logCyclicObjectToConsole, stringify : stringify, parse : parse } function setObject(name, object){ var str = stringify(object); localStorage.setItem(name, str); } function getObject(name){ var str = localStorage.getItem(name); if (str===null) return null; return parse(str); } return { CYCLICJSON : CYCLICJSON, setObject : setObject, getObject : getObject } })(); obj = { L: { L: { v: 'lorem' }, R: { v: 'ipsum' } }, R: { L: { v: 'dolor' }, R: { L: { v: 'sit' }, R: { v: 'amet' } } } } obj.RLuncle = obj.L; obj.RRuncle = obj.L; obj.RRLuncle = obj.RL; obj.RRRuncle = obj.RL; obj.LLuncle = obj.R; obj.LRuncle = obj.R; // LOCALSTORAGE.setObject('latinUncles', obj) // recovered = LOCALSTORAGE.getObject('latinUncles') // localStorage not available inside fiddle ): LOCALSTORAGE.CYCLICJSON.logCyclicObjectToConsole(obj) putIntoLS = LOCALSTORAGE.CYCLICJSON.stringify(obj); recovered = LOCALSTORAGE.CYCLICJSON.parse(putIntoLS); LOCALSTORAGE.CYCLICJSON.logCyclicObjectToConsole(recovered); var the = document.getElementById('the'); the.textContent = the.textContent + '\n\n' + JSON.stringify( [ obj.LLv === recovered.LLv, obj.LRv === recovered.LRv, obj.RLv === recovered.RLv, obj.RRLv === recovered.RRLv, obj.RRRv === recovered.RRRv, obj.RLuncle === obj.L, obj.RRuncle === obj.L, obj.RRLuncle === obj.RL, obj.RRRuncle === obj.RL, obj.LLuncle === obj.R, obj.LRuncle === obj.R, recovered.RLuncle === recovered.L, recovered.RRuncle === recovered.L, recovered.RRLuncle === recovered.RL, recovered.RRRuncle === recovered.RL, recovered.LLuncle === recovered.R, recovered.LRuncle === recovered.R ] )
<pre id='the'></pre>
mathheadinclouds순환 참조
이 답변에서는 순환 참조가 있는 데이터 전용 개체(함수 등 없음)에 중점을 두고 maja 및 mathheadinclouds에서 언급한 아이디어를 개발합니다(나는 그의 테스트 케이스를 사용하고 내 코드는 몇 배 더 짧습니다). 사실 우리가 적절한으로 JSON.stringify을 사용할 수있는 대체물 - 소스 객체가 어떤 객체에 다중 참조를 포함, 또는 우리가 특별한 경로 문자열을 참조하는 다음 순환 참조를 포함하는 경우 (유사 JSONPath )
// JSON.strigify replacer for objects with circ ref function refReplacer() { let m = new Map(), v= new Map(), init = null; return function(field, value) { let p= m.get(this) + (Array.isArray(this) ? `[${field}]` : '.' + field); let isComplex= value===Object(value) if (isComplex) m.set(value, p); let pp = v.get(value)||''; let path = p.replace(/undefined\.\.?/,''); let val = pp ? `#REF:${pp[0]=='[' ? '$':'$.'}${pp}` : value; !init ? (init=value) : (val===init ? val="#REF:$" : 0); if(!pp && isComplex) v.set(value, path); return val; } } // --------------- // TEST // --------------- // gen obj with duplicate/circular references let obj = { L: { L: { v: 'lorem' }, R: { v: 'ipsum' } }, R: { L: { v: 'dolor' }, R: { L: { v: 'sit' }, R: { v: 'amet' } } } } obj.RLuncle = obj.L; obj.RRuncle = obj.L; obj.RRLuncle = obj.RL; obj.RRRuncle = obj.RL; obj.LLuncle = obj.R; obj.LRuncle = obj.R; testObject = obj; let json = JSON.stringify(testObject, refReplacer(), 4); console.log("Test Object\n", testObject); console.log("JSON with JSONpath references\n",json);
JSONpath와 같은 참조를 사용하여 이러한 json을 구문 분석합니다.
// parse json with JSONpath references to object function parseRefJSON(json) { let objToPath = new Map(); let pathToObj = new Map(); let o = JSON.parse(json); let traverse = (parent, field) => { let obj = parent; let path = '#REF:$'; if (field !== undefined) { obj = parent[field]; path = objToPath.get(parent) + (Array.isArray(parent) ? `[${field}]` : `${field?'.'+field:''}`); } objToPath.set(obj, path); pathToObj.set(path, obj); let ref = pathToObj.get(obj); if (ref) parent[field] = ref; for (let f in obj) if (obj === Object(obj)) traverse(obj, f); } traverse(o); return o; } // --------------- // TEST 1 // --------------- let json = ` { "L": { "L": { "v": "lorem", "uncle": { "L": { "v": "dolor", "uncle": "#REF:$.L" }, "R": { "L": { "v": "sit", "uncle": "#REF:$.LLuncle.L" }, "R": { "v": "amet", "uncle": "#REF:$.LLuncle.L" }, "uncle": "#REF:$.L" } } }, "R": { "v": "ipsum", "uncle": "#REF:$.LLuncle" } }, "R": "#REF:$.LLuncle" }`; let testObject = parseRefJSON(json); console.log("Test Object\n", testObject); // --------------- // TEST 2 // --------------- console.log('Tests from mathheadinclouds anser:'); let recovered = testObject; let obj = { // original object L: { L: { v: 'lorem' }, R: { v: 'ipsum' } }, R: { L: { v: 'dolor' }, R: { L: { v: 'sit' }, R: { v: 'amet' } } } } obj.RLuncle = obj.L; obj.RRuncle = obj.L; obj.RRLuncle = obj.RL; obj.RRRuncle = obj.RL; obj.LLuncle = obj.R; obj.LRuncle = obj.R; [ obj.LLv === recovered.LLv, obj.LRv === recovered.LRv, obj.RLv === recovered.RLv, obj.RRLv === recovered.RRLv, obj.RRRv === recovered.RRRv, obj.RLuncle === obj.L, obj.RRuncle === obj.L, obj.RRLuncle === obj.RL, obj.RRRuncle === obj.RL, obj.LLuncle === obj.R, obj.LRuncle === obj.R, recovered.RLuncle === recovered.L, recovered.RRuncle === recovered.L, recovered.RRLuncle === recovered.RL, recovered.RRRuncle === recovered.RL, recovered.LLuncle === recovered.R, recovered.LRuncle === recovered.R ].forEach(x=> console.log('test pass: '+x));
결과 json을 스토리지에 로드/저장하려면 다음 코드를 사용하십시오.
localStorage.myObject = JSON.stringify(testObject, refReplacer()); // save testObject = parseRefJSON(localStorage.myObject); // load
Kamil Kiełczewski나는 Jackson-js를 사용하는 것이 좋습니다. 이것은 데코레이터를 기반으로 구조를 유지하면서 객체의 직렬화 및 역직렬화를 처리하는 라이브러리입니다.
라이브러리는 순환 참조, 속성 앨리어싱 등과 같은 모든 함정을 처리합니다.
@JsonProperty() @JsonClassType() 데코레이터를 사용하여 클래스를 설명하기만 하면 다음을 사용하여 객체를 직렬화할 수 있습니다.
const objectMapper = new ObjectMapper(); localstore.setItem(key, objectMapper.stringify<yourObjectType>(yourObject));
약간 더 자세한 설명은 여기에서 내 대답을 확인하십시오.
https://stackoverflow.com/a/66706365/1146499
그리고 여기에 Jackson-js 튜토리얼이 있습니다:
https://itnext.io/jackson-js-powerful-javascript-decorators-to-serialize-deserialize-objects-into-json-and-vice-df952454cf
Gabriel H이 질문은 JavaScript 전용 관점에서 충분히 답변되었으며, 다른 사람들은 이미 localStorage.getItem
및 localStorage.setItem
모두 객체에 대한 개념이 없으며 문자열과 문자열만 처리한다는 점에 주목했습니다. 이 답변은 JavaScript 전용 솔루션에서 다른 사람들 이 제안한 것을 통합한 TypeScript 친화적 솔루션을 제공합니다.
타입스크립트 4.2.3
Storage.prototype.setObject = function (key: string, value: unknown) { this.setItem(key, JSON.stringify(value)); }; Storage.prototype.getObject = function (key: string) { const value = this.getItem(key); if (!value) { return null; } return JSON.parse(value); }; declare global { interface Storage { setObject: (key: string, value: unknown) => void; getObject: (key: string) => unknown; } }
용법
localStorage.setObject('ages', [23, 18, 33, 22, 58]); localStorage.getObject('ages');
설명
Storage
프로토타입 setObject
및 getObject
함수를 모두 선언합니다. localStorage
는 이 유형의 인스턴스입니다. getObject
의 null 처리 외에 특별히 주의해야 할 사항은 없습니다. getItem
null
을 반환할 수 있으므로 null
값에 대해 JSON.parse
를 호출하면 런타임 예외가 발생하므로 일찍 종료해야 합니다.
Storage
프로토타입에서 함수를 선언한 후 전역 네임스페이스 Storage
유형에 대한 유형 정의를 포함합니다.
참고: 화살표 함수로 이러한 함수를 정의한 경우 호출하는 저장소 개체가 항상 localStorage
라고 가정해야 하며 이는 사실이 아닐 수 있습니다. 예를 들어 위의 코드는 setObject
및 getObject
지원도 sessionStorage
추가합니다.
dwlzlocalStorage.setItem('user', JSON.stringify(user));
그런 다음 저장소에서 검색하고 객체로 다시 변환하려면 다음을 수행합니다.
var user = JSON.parse(localStorage.getItem('user')); If we need to delete all entries of the store we can simply do: localStorage.clear();
manasa woddeyar manu출처 : http:www.stackoverflow.com/questions/2010892/storing-objects-in-html5-localstorage