ES6 맵을 JSON.stringify하는 방법은 무엇입니까?


105

JS 객체 대신 ES6 Map을 사용하고 싶지만 JSON.stringify ()지도를 만드는 방법을 알 수 없기 때문에 보류되고 있습니다. 내 키는 문자열로 보장되며 내 값은 항상 나열됩니다. 직렬화하려면 래퍼 메서드를 작성해야합니까?


1
주제에 대한 흥미로운 기사 2ality.com/2015/08/es6-map-json.html
데이비드 체이스

나는 이것을 작동시킬 수 있었다. 결과는 embed.plnkr.co/oNlQQBDyJUiIQlgWUPVP의 Plunkr에 있습니다. 이 솔루션은 JSON.stringify (obj, replacerFunction)를 사용하여 Map 객체가 전달되는지 확인하고 Map 객체를 Javascript 객체 (JSON.stringify)로 변환 한 다음 문자열로 변환합니다.
PatS

1
키가 문자열 (또는 숫자)이고 값 배열 이 보장되는 경우 다음과 같이 할 수 있습니다 [...someMap.entries()].join(';'). 당신은 같은 것을 사용하여 비슷한 일을 시도 할 수 있습니다 더 복잡한 뭔가[...someMap.entries()].reduce((acc, cur) => acc + `${cur[0]}:${/* do something to stringify cur[1] */ }`, '')
user56reinstatemonica8

@Oriol 키 이름이 기본 속성과 같을 수 있다면 어떨까요? obj[key]예상치 못한 것을 얻을 수 있습니다. 사례를 고려하십시오 if (!obj[key]) obj[key] = newList; else obj[key].mergeWith(newList);.
Franklin Yu

답변:


65

당신은 할 수 없습니다.

지도의 키는 객체를 포함하여 무엇이든 될 수 있습니다. 그러나 JSON 구문은 문자열을 키로 만 허용합니다. 따라서 일반적인 경우에는 불가능합니다.

내 키는 문자열이 보장되고 내 값은 항상 목록이됩니다.

이 경우 일반 개체를 사용할 수 있습니다. 다음과 같은 장점이 있습니다.

  • JSON으로 문자열화할 수 있습니다.
  • 이전 브라우저에서 작동합니다.
  • 더 빠를 수 있습니다.

31
호기심 많은 최신 크롬, 모든지도는 '{}'로 직렬화
Capaj

나는 내가 "할 수 없다"고 말했을 때 내가 정확히 무엇을 의미하는지 여기에서 설명했다 .
Oriol

7
"더 빠를 수도 있습니다"-그것에 대한 출처가 있습니까? 나는 단순한 해시 맵이 완전한 물체보다 빠르다고 상상하고 있지만 증거가 없습니다. :)
Lilleman

1
@Xplouder 그 테스트는 값 비싼 hasOwnProperty. 이것이 없으면 Firefox는지도보다 훨씬 빠르게 개체를 반복합니다. 하지만 Chrome에서는지도가 여전히 더 빠릅니다. jsperf.com/es6-map-vs-object-properties/95
오리올

1
사실, Firefox 45v는 Chrome + 49v보다 빠르게 개체를 반복하는 것 같습니다. 그러나지도는 여전히 Chrome에서 개체 대비 승리합니다.
Xplouder

71

Map속성이 없기 때문에 인스턴스를 직접 문자열화할 수는 없지만 튜플 배열로 변환 할 수 있습니다.

jsonText = JSON.stringify(Array.from(map.entries()));

반대의 경우

map = new Map(JSON.parse(jsonText));

6
이것은 JSON 객체로 변환되지 않고 대신 배열의 배열로 변환됩니다. 같은 것이 아닙니다. 더 완전한 답변은 아래 Evan Carroll의 답변을 참조하십시오.
토요일 Thiru

3
@SatThiru 튜플의 배열은 Maps 의 관례적인 표현이며 생성자 및 반복자와 잘 어울립니다. 또한 문자열이 아닌 키가있는 맵의 유일한 현명한 표현이며 객체는 거기에서 작동하지 않습니다.
Bergi

Bergi, OP는 "내 키는 문자열로 보장됩니다"라고 말했습니다.
토요일 Thiru


@Bergi Stringify key는 객체 인 경우 작동하지 않습니다 ( 예 "{"[object Object]":{"b":2}}": 객체 키가지도의 주요 기능 중
하나임)

59

모두 JSON.stringifyJSON.parse두 번째 인수를 지원합니다. replacer그리고 reviver각각. 아래의 replacer 및 reviver를 사용하면 깊이 중첩 된 값을 포함하여 기본 Map 개체에 대한 지원을 추가 할 수 있습니다.

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;
}

사용법 :

const originalValue = new Map([['a', 1]]);
const str = JSON.stringify(originalValue, replacer);
const newValue = JSON.parse(str, reviver);
console.log(originalValue, newValue);

배열, 객체 및 맵의 조합을 사용한 깊은 중첩

const originalValue = [
  new Map([['a', {
    b: {
      c: new Map([['d', 'text']])
    }
  }]])
];
const str = JSON.stringify(originalValue, replacer);
const newValue = JSON.parse(str, reviver);
console.log(originalValue, newValue);

8
이는 지금까지 가장 좋은 반응이다
마누엘 베라 실베스트르

1
여기에서 확실히 가장 좋은 대답입니다.
JavaRunner

15

아직 ecmascript에서 제공하는 메서드는 없지만 을 JavaScript 기본 형식에 JSON.stingify매핑하는 경우 계속 사용할 수 있습니다 Map. 다음은 Map우리가 사용할 샘플 입니다.

const map = new Map();
map.set('foo', 'bar');
map.set('baz', 'quz');

자바 스크립트 개체로 이동

다음 도우미 함수를 사용하여 JavaScript 개체 리터럴로 변환 할 수 있습니다.

const mapToObj = m => {
  return Array.from(m).reduce((obj, [key, value]) => {
    obj[key] = value;
    return obj;
  }, {});
};

JSON.stringify(mapToObj(map)); // '{"foo":"bar","baz":"quz"}'

객체의 JavaScript 배열로 이동

이것에 대한 도우미 기능은 훨씬 더 간결합니다

const mapToAoO = m => {
  return Array.from(m).map( ([k,v]) => {return {[k]:v}} );
};

JSON.stringify(mapToAoO(map)); // '[{"foo":"bar"},{"baz":"quz"}]'

배열 배열로 이동

이것은 더 쉽습니다.

JSON.stringify( Array.from(map) ); // '[["foo","bar"],["baz","quz"]]'

13

스프레드 구문 맵을 사용하여 한 줄로 직렬화 할 수 있습니다.

JSON.stringify([...new Map()]);

다음을 사용하여 역 직렬화합니다.

let map = new Map(JSON.parse(map));

1 차원지도에서는 ​​작동하지만 n 차원지도에서는 ​​작동하지 않습니다.
mattsven

6

Map인스턴스 문자열 화 (객체를 키로해도 괜찮음) :

JSON.stringify([...map])

또는

JSON.stringify(Array.from(map))

또는

JSON.stringify(Array.from(map.entries()))

출력 형식:

// [["key1","value1"],["key2","value2"]]

4

더 나은 솔루션

    // somewhere...
    class Klass extends Map {

        toJSON() {
            var object = { };
            for (let [key, value] of this) object[key] = value;
            return object;
        }

    }

    // somewhere else...
    import { Klass as Map } from '@core/utilities/ds/map';  // <--wherever "somewhere" is

    var map = new Map();
    map.set('a', 1);
    map.set('b', { datum: true });
    map.set('c', [ 1,2,3 ]);
    map.set( 'd', new Map([ ['e', true] ]) );

    var json = JSON.stringify(map, null, '\t');
    console.log('>', json);

산출

    > {
        "a": 1,
        "b": {
            "datum": true
        },
        "c": [
            1,
            2,
            3
        ],
        "d": {
            "e": true
        }
    }

위의 답변보다 덜 까다롭기를 바랍니다.


많은 사람들이 핵심 맵 클래스를 json으로 직렬화하기 위해 확장하는 데 만족할 것 같지 않습니다.
vasia

1
꼭 그래야 할 필요는 없지만 더 확실한 방법입니다. 특히 이것은 SOLID의 LSP 및 OCP 원칙과 일치합니다. 즉, 네이티브 맵은 수정되지 않고 확장되고 있으며 네이티브 맵과 함께 Liskov Substitution (LSP)을 계속 사용할 수 있습니다. 물론, 많은 초심자 나 충실한 기능적 프로그래밍 사람들이 선호하는 것보다 OOP가 더 많지만 적어도 기본 소프트웨어 설계 원칙의 검증 된 기준에 얽매여 있습니다. SOLID의 ISP (Interface Segregation Principle)를 구현하려는 경우 작은 IJSONAble인터페이스 를 사용할 수 있습니다 (물론 TypeScript 사용).
Cody

3

아래 솔루션은 중첩 된지도가 있더라도 작동합니다.

function stringifyMap(myMap) {
    function selfIterator(map) {
        return Array.from(map).reduce((acc, [key, value]) => {
            if (value instanceof Map) {
                acc[key] = selfIterator(value);
            } else {
                acc[key] = value;
            }

            return acc;
        }, {})
    }

    const res = selfIterator(myMap)
    return JSON.stringify(res);
}

귀하의 답변을 테스트하지 않고 이미 중첩 된지도의 문제에 대한 관심을 불러 일으키는 방법에 감사드립니다. 이것을 JSON으로 성공적으로 변환하더라도 향후 수행되는 모든 구문 분석은 JSON이 원래 Map였고 (더 나쁜) 각 하위 맵 (포함)도 원래 맵 이라는 것을 명시 적으로 인식해야합니다 . 그렇지 않으면 array of pairs이지도가 아니라 정확히 의도 된 것이 아니라는 것을 확인할 수있는 방법 이 없습니다. 객체 및 배열의 ​​계층 구조는 구문 분석시 이러한 부담을주지 않습니다. 의 적절한 직렬화는 Map그것이 Map.
Lonnie Best

여기 에 대해 자세히 알아 보십시오 .
Lonnie Best
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.