ES6 맵을 로컬 스토리지(또는 다른 곳)에 보관하려면 어떻게 해야 합니까?
var a = new Map([[ 'a', 1 ]]);
a.get('a') // 1
var forStorageSomewhere = JSON.stringify(a);
// Store, in my case, in localStorage.
// Later:
var a = JSON.parse(forStorageSomewhere);
a.get('a') // TypeError: undefined is not a function
도 ★★★★★★★★★★★★★★★.JSON.stringify(a);
'{}'을(를) 사용하다이는 복원 시 가 빈 객체가 된다는 것을 의미합니다.
맵과 플레인 오브젝트 사이에서 업/다운캐스팅이 가능한 es6-mapify를 발견했기 때문에 하나의 솔루션일 수도 있지만 단순히 맵을 유지하기 위해 외부 의존성에 의존할 필요가 있다고 생각했습니다.
키와 값을 모두 직렬화할 수 있다고 가정하면
localStorage.myMap = JSON.stringify(Array.from(map.entries()));
작동해야 합니다.반대의 경우는,
map = new Map(JSON.parse(localStorage.myMap));
깨끗함:
JSON.stringify([...myMap])
일반적으로 직렬화는 이 속성이 유지되는 경우에만 유용합니다.
deserialize(serialize(data)).get(key) ≈ data.get(key)
서 ''는a ≈ b
라고 할 수 serialize(a) === serialize(b)
.
이는 개체를 JSON에 직렬화할 때 충족됩니다.
var obj1 = {foo: [1,2]},
obj2 = JSON.parse(JSON.stringify(obj1));
obj1.foo; // [1,2]
obj2.foo; // [1,2] :)
JSON.stringify(obj1.foo) === JSON.stringify(obj2.foo); // true :)
속성에는 문자열만 사용할 수 있으며 문자열에 무손실 직렬화할 수 있습니다.
단, ES6 맵에서는 임의의 값을 키로 사용할 수 있습니다.이는 객체가 데이터가 아닌 참조로 고유하게 식별되기 때문에 문제가 됩니다.개체를 직렬화할 때 참조가 손실됩니다.
var key = {},
map1 = new Map([ [1,2], [key,3] ]),
map2 = new Map(JSON.parse(JSON.stringify([...map1.entries()])));
map1.get(1); // 2
map2.get(1); // 2 :)
map1.get(key); // 3
map2.get(key); // undefined :(
그래서 나는 일반적으로 그것을 유용한 방법으로 하는 것은 불가능하다고 말하고 싶다.
그리고 이 경우 지도 대신 일반 객체를 사용할 수 있습니다.이 방법에는 다음과 같은 이점도 있습니다.
- 키 정보를 잃지 않고 JSON에 문자열화할 수 있습니다.
- 오래된 브라우저에서는 동작합니다.
- 그게 더 빠를 수도 있어요.
Oriol의 대답을 바탕으로 우리는 조금 더 잘할 수 있다.원시 루트 또는 맵 입구가 존재하는 한 오브젝트 참조를 키에 사용할 수 있으며 각 오브젝트 키는 해당 루트 키에서 임시로 찾을 수 있습니다.
Douglas Crockford의 JSON.decycle 및 JSON.retrocycle을 사용하도록 Oriol의 예를 수정하면 이 경우를 처리하는 맵을 만들 수 있습니다.
var key = {},
map1 = new Map([ [1, key], [key, 3] ]),
map2 = new Map(JSON.parse(JSON.stringify([...map1.entries()]))),
map3 = new Map(JSON.retrocycle(JSON.parse(JSON.stringify(JSON.decycle([...map1.entries()])))));
map1.get(1); // key
map2.get(1); // key
map3.get(1); // key
map1.get(map1.get(1)); // 3 :)
map2.get(map2.get(1)); // undefined :(
map3.get(map3.get(1)); // 3 :)
10진수 및 역주기를 통해 JSON에서 순환 구조와 대그를 인코딩할 수 있습니다.오브젝트 자체에 추가 속성을 작성하지 않고 오브젝트 간의 관계를 구축하거나 ES6 Map을 사용하여 오브젝트 및 비자 버전과 원본을 상호 연관짓는 경우 유용합니다.
한 가지 문제는 원래 키 오브젝트를 새로운 맵에 사용할 수 없다는 것입니다(map3.get(key);
의다만, 원래의 키 참조를 보관 유지하고 있습니다만, 새롭게 해석된 JSON 맵은, 지금까지 없었던 매우 드문 케이스인 것 같습니다.
사용자 고유의 기능을 구현한 경우class
일반적인 오래된 오브젝트만 있으면 됩니다.
Map
는 을 sArray
★★★★★★★★★★★★★★★★★? Map
사람과 함께 하다Map
★★★★★★★★★★★★★★★★★*Map
Object
이치노
Map.prototype.toJSON = function() {
return Array.from(this.entries());
};
바로 그거야!prototype manipulation is required here. You could go around adding toJSON()
manually to all your non-standard stuff, but really you're just avoiding the power of JS
test = {
regular : 'object',
map : new Map([
[['array', 'key'], 7],
['stringKey' , new Map([
['innerMap' , 'supported'],
['anotherValue', 8]
])]
])
};
console.log(JSON.stringify(test));
출력:
{"regular":"object","map":[[["array","key"],7],["stringKey",[["innerMap","supported"],["anotherValue",8]]]]}
로 Map
s는 자동적이지는 않습니다.위의 문자열을 사용하여 맵을 리메이크하여 값을 추출합니다.
test2 = JSON.parse(JSON.stringify(test));
console.log((new Map((new Map(test2.map)).get('stringKey'))).get('innerMap'));
출력
"supported"
조금 지저분하지만 약간의 매직소스로 탈직렬화 자동화를 할 수도 있습니다.
Map.prototype.toJSON = function() {
return ['window.Map', Array.from(this.entries())];
};
Map.fromJSON = function(key, value) {
return (value instanceof Array && value[0] == 'window.Map') ?
new Map(value[1]) :
value
;
};
이제 JSON은
{"regular":"object","test":["window.Map",[[["array","key"],7],["stringKey",["window.Map",[["innerMap","supported"],["anotherValue",8]]]]]]}
및 .Map.fromJSON
test2 = JSON.parse(JSON.stringify(test), Map.fromJSON);
console.log(test2.map.get('stringKey').get('innerMap'));
no "no" (no)" (no)new Map()
(사용)
"supported"
다중 치수 맵이 있는 경우 승인된 답변은 실패합니다.Map 객체는 다른 Map 객체를 키 또는 값으로 사용할 수 있습니다.
따라서 이 작업을 보다 안전하고 효율적으로 처리하는 방법은 다음과 같습니다.
function arrayifyMap(m){
return m.constructor === Map ? [...m].map(([v,k]) => [arrayifyMap(v),arrayifyMap(k)])
: m;
}
일단 이 툴을 손에 넣으면, 언제라도 「좋아요」를 실행할 수 있습니다.
localStorage.myMap = JSON.stringify(arrayifyMap(myMap))
// store
const mapObj = new Map([['a', 1]]);
localStorage.a = JSON.stringify(mapObj, replacer);
// retrieve
const newMapObj = JSON.parse(localStorage.a, reviver);
// required replacer and reviver functions
function replacer(key, value) {
const originalObject = this[key];
if(originalObject instanceof Map) {
return {
dataType: 'Map',
value: Array.from(originalObject.entries()), // or with spread: value: [...originalObject]
};
} else {
return value;
}
}
function reviver(key, value) {
if(typeof value === 'object' && value !== null) {
if (value.dataType === 'Map') {
return new Map(value.value);
}
}
return value;
}
리페이서 및 리바이버 함수에 대한 설명은 https://stackoverflow.com/a/56150320/696535에 기재했습니다.
이 코드는 일반 JSON.stringify와 같은 다른 값에 대해 작동하므로 직렬화된 개체가 Map이어야 한다는 가정은 없습니다.배열 또는 객체에 깊이 중첩된 맵일 수도 있습니다.
한 가지 누락되는 것은 맵이 주문형 구조라는 점입니다. 즉, 입력한 첫 번째 항목을 반복할 때 가장 먼저 나열됩니다.
이것은 Javascript 오브젝트와는 다릅니다.저는 이런 종류의 구조를 요구했습니다(그래서 Map을 사용했습니다).그리고 JSON.stringify가 작동하지 않는다는 것을 알게 되었습니다(하지만 이해할 수 있습니다).
결국 가장 기본적인 '타입'에 대해서만 JSON.stringify를 사용하여 Everything을 해석하는 'value_to_json' 함수를 만들었습니다.
유감스럽게도 MAP을 .toJSON()으로 서브클래싱하는 것은 JSON_string이 아닌 값을 제외하고 동작하지 않습니다.또한 그것은 유산으로 여겨진다.
하지만 제 활용 사례는 예외적일 것입니다.
관련:
- https://github.com/DavidBruant/Map-Set.prototype.toJSON/issues/16
- JSON은 Infinity와 NaN을 생략했습니다. ECMAScript에서 JSON 상태는?
- ES5 세트 및 맵을 포함하는 개체를 문자열화하려면 어떻게 해야 합니까?
- JSON 문자열화
function value_to_json(value) {
if (value === null) {
return 'null';
}
if (value === undefined) {
return 'null';
}
//DEAL WITH +/- INF at your leisure - null instead..
const type = typeof value;
//handle as much as possible taht have no side effects. function could
//return some MAP / SET -> TODO, but not likely
if (['string', 'boolean', 'number', 'function'].includes(type)) {
return JSON.stringify(value)
} else if (Object.prototype.toString.call(value) === '[object Object]') {
let parts = [];
for (let key in value) {
if (Object.prototype.hasOwnProperty.call(value, key)) {
parts.push(JSON.stringify(key) + ': ' + value_to_json(value[key]));
}
}
return '{' + parts.join(',') + '}';
}
else if (value instanceof Map) {
let parts_in_order = [];
value.forEach((entry, key) => {
if (typeof key === 'string') {
parts_in_order.push(JSON.stringify(key) + ':' + value_to_json(entry));
} else {
console.log('Non String KEYS in MAP not directly supported');
}
//FOR OTHER KEY TYPES ADD CUSTOM... 'Key' encoding...
});
return '{' + parts_in_order.join(',') + '}';
} else if (typeof value[Symbol.iterator] !== "undefined") {
//Other iterables like SET (also in ORDER)
let parts = [];
for (let entry of value) {
parts.push(value_to_json(entry))
}
return '[' + parts.join(',') + ']';
} else {
return JSON.stringify(value)
}
}
let m = new Map();
m.set('first', 'first_value');
m.set('second', 'second_value');
let m2 = new Map();
m2.set('nested', 'nested_value');
m.set('sub_map', m2);
let map_in_array = new Map();
map_in_array.set('key', 'value');
let set1 = new Set(["1", 2, 3.0, 4]);
m2.set('array_here', [map_in_array, "Hello", true, 0.1, null, undefined, Number.POSITIVE_INFINITY, {
"a": 4
}]);
m2.set('a set: ', set1);
const test = {
"hello": "ok",
"map": m
};
console.log(value_to_json(test));
js localStorage API를 사용하여 ES6 맵을 저장합니다.
버그
"[object Map]" ❌
(() => {
const map = new Map();
map.set(1, {id: 1, name: 'eric'});
// Map(1) {1 => {…}}
// ❌
localStorage.setItem('app', map);
localStorage.getItem('app');
// "[object Map]"
})();
해결 방법
사용하다
JSON.stringify
를 연재하다Map
저장하고 사용하기 전에 오브젝트JSON.parse
에 액세스하기 전에 시리얼을 해제한다.Map
오브젝트 ✅
(() => {
const map = new Map();
map.set(1, {id: 1, name: 'eric'});
// Map(1) {1 => {…}}
// ✅
localStorage.setItem('app', JSON.stringify([...map]));
const newMap = new Map(JSON.parse(localStorage.getItem('app')));
// Map(1) {1 => {…}}
})();
스크린샷
참조
https://www.cnblogs.com/xgqfrms/p/14431425.html
큰 지도 컬렉션에서 setItem을 시도하면 느려진다는 것을 기억해야 합니다.저는 168590 엔트리가 있는 지도를 로컬 스토리지에 유지하려고 했는데 이 오류가 발생했습니다. : (
언급URL : https://stackoverflow.com/questions/28918232/how-do-i-persist-a-es6-map-in-localstorage-or-elsewhere
'programing' 카테고리의 다른 글
브라우저에서 AJAX(XmlHttpRequest) 콜의 타임아웃을 검출하려면 어떻게 해야 합니까? (0) | 2023.03.11 |
---|---|
사용자가 페이지를 떠난 후 php 실행이 중지됩니까? (0) | 2023.03.11 |
Wordpress에서 이미지를 비공개로 설정 (0) | 2023.03.11 |
"woocommerce_add_to_cart" 필터 또는 후크를 추가하는 방법 (0) | 2023.03.11 |
REST API - "Accept: application/json" HTTP 헤더 사용 (0) | 2023.03.11 |