programing

ES6 맵을 로컬 스토리지(또는 다른 곳)에 보관하려면 어떻게 해야 합니까?

css3 2023. 3. 11. 09:20

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.decycleJSON.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★★★★★★★★★★★★★★★★★*MapObject이치노

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이 아닌 값을 제외하고 동작하지 않습니다.또한 그것은 유산으로 여겨진다.

하지만 제 활용 사례는 예외적일 것입니다.

관련:

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