일반 객체를 ES6 맵으로 변환하는 방법은 무엇입니까?


128

어떤 이유로 MDN 문서 에서이 간단한 것을 찾을 수 없습니다 (아마도 그냥 놓치고있을 수도 있습니다).

나는 이것이 작동 할 것으로 예상했다.

const map = new Map({foo: 'bar'});

map.get('foo'); // 'bar'

...하지만 첫 번째 줄은 TypeError: (var)[Symbol.iterator] is not a function

일반 개체에서지도를 만들려면 어떻게해야합니까? 먼저 키-값 쌍의 배열로 변환해야합니까?


2
FWIW, 그것은 가치에서 허용 대답을 전환 할 수있다 광산NILS ' 또는 BERGI의를 . Object.entries실제로는보다 나은 접근 방식 Object.keys이며 bergi의 생성기 함수 접근 방식은 Object.keys또는 Object.entries.
TJ Crowder

답변:


195

예, Map생성자는 키-값 쌍의 배열을 사용합니다.

Object.entriesES2017 (19.1.2.5) 에서 사용할 수있는 새로운 Object 정적 메서드 입니다.

const map = new Map(Object.entries({foo: 'bar'}));

map.get('foo'); // 'bar'

현재 Firefox 46 이상 및 Edge 14 이상 및 최신 버전의 Chrome에서 구현됩니다.

이전 환경을 지원해야하고 트랜스 파일이 옵션이 아닌 경우 georg에서 권장하는 것과 같은 polyfill을 사용하세요.

Object.entries = typeof Object.entries === 'function' ? Object.entries : obj => Object.keys(obj).map(k => [k, obj[k]]);

3
"polyfill"은 다소 사소한 것입니다.Object.entries = obj => Object.keys(obj).map(k => [k, obj[k]])
georg

4
Object.entriesBTW (플래그 없음) 적절한 노드 7.x에서 착륙
리 벤슨

2
Node7의 Object.entries 일뿐만 아니라 ES2017 최종 사양의 일부이기도합니다. 따라서 이것은 받아 들여진 대답이어야합니다. IMO
AnilRedshift

1
@AnilRedshift- OP가 중개자를 피하는 솔루션을 요청했기 때문에 이것이 또는 생성기 함수 대답 입니다.
TJ Crowder

2
불행히도 그렇지 않습니다.
Nemanja Milosavljevic

78

생성기 함수를 사용 하여 nils의 답변Object.entries 및 / 또는 bergi의 답변을 참조하십시오. . 하지만 Object.entries문제는 질문을 받았다 때 아직 사양에 없었다, 그것은 4 단계에 있었다 하더라도 다시 2016년 4월 (단지)에서에 polyfill 사용하기 때문에 안전합니다. ( 여기 에 더 많은 단계가 있습니다 .) 그리고 생성기 함수는 ES2015에있었습니다. OP는 특히 중개자를 피하도록 요청했으며 발전기가 그것을 완전히 피하지는 않지만 아래 또는 (약간)보다 더 나은 작업을 수행합니다.Object.enties .

FWIW, 사용 Object.entries:

  • [name, value]전달할 배열의 배열을 만듭니다.new Map
  • 그만큼 Map생성자는 반복자를 얻을 수있는 배열 함수를 호출; 배열은 배열 인터 레이터 객체를 생성하고 반환합니다.
  • 그만큼 Map반복자 객체가 엔트리합니다 (얻을 것을 생성자가 사용하는 [name, value]배열)과지도를 구축

생성기 사용 :

  • 제너레이터 함수를 호출 한 결과로 제너레이터 객체를 생성합니다.
  • Map생성자는 그것에서 반복자를 얻기 위해 그 발전기 객체에 함수를 호출; 생성기 객체는 자신을 반환 합니다.
  • Map생성자 (반복자로) 발전기 객체의 항목합니다 (얻기 위해 사용하는 [name, value]배열)과지도를 구축

따라서 : 하나 더 적은 중개자 (의 배열 Object.entries).

그러나 사용 Object.entries이 더 간단하고 해당 어레이를 만드는 것이 99.999 %의 시간에 문제가되지 않습니다. 그러니 둘 중 하나입니다. 그러나 둘 다 아래보다 낫습니다. :-)


원래 답변 :

을 초기화하려면 Map배열 배열과 같이 키 / 값 쌍을 배열로 반환하는 반복기를 사용할 수 있습니다.

const map = new Map([
    ['foo', 'bar']
]);

객체에서지도로의 기본 변환은 없지만 다음을 사용하여 쉽게 수행 할 수 있습니다 Object.keys.

const map = new Map();
let obj = {foo: 'bar'};
Object.keys(obj).forEach(key => {
    map.set(key, obj[key]);
});

물론이를 처리 할 작업자 함수를 제공 할 수 있습니다.

function buildMap(obj) {
    let map = new Map();
    Object.keys(obj).forEach(key => {
        map.set(key, obj[key]);
    });
    return map;
}

그때

const map = buildMap({foo: 'bar'});

또는 여기에 더 l33t-looking (아직도 문제가 있습니까?) 버전이 있습니다.

function buildMap(obj) {
    return Object.keys(obj).reduce((map, key) => map.set(key, obj[key]), new Map());
}

(예, Map#set지도 참조를 반환합니다. 어떤이는 것입니다 주장 abusagereduce.)

또는 우리는 모호성에 대해 정말로 과장 할 수 있습니다 .

const buildMap = o => Object.keys(o).reduce((m, k) => m.set(k, o[k]), new Map());

아니, 절대 그렇게하지 않을거야. :-)


1
@Ohar와 @TJCrowder의 솔루션 융합 : var buildMap2 = o => new Map(Object.keys(o).map(k => [k, o[k]]));.
7vujy0f0hy 2011 년

17
new Map(Object.entries(object)) stackoverflow.com/a/36644558/798133
Rafael Xavier

Object.entries 답변을 선호해야합니다
Kir

@Kir- 저것 또는 발전기 , 예. 내 편집을 참조하십시오.
TJ Crowder

31

먼저 키-값 쌍의 배열로 변환해야합니까?

아니요, 키-값 쌍 배열의 반복자로 충분합니다. 다음을 사용하여 중간 배열 생성을 피할 수 있습니다.

function* entries(obj) {
    for (let key in obj)
        yield [key, obj[key]];
}

const map = new Map(entries({foo: 'bar'}));
map.get('foo'); // 'bar'

좋은 예-다른 사람들에게 참고로 if(!obj.hasOwnProperties(key)) continue;, 객체 프로토 타입에서 상속 된 속성을 생성하지 않도록 for 루프 조건 직후 에 수행 할 수 있습니다 (객체를 신뢰하지 않는 한, 객체를 반복 할 때 in좋은 습관으로).
푸 이우

2
@Puiu 아니, 당신은 안되며 나쁜 습관입니다. 만약 당신이 그 물건을 신뢰하지 않는다면, 당신은 그것의 .hasOwnProperty재산도 믿어서는 안되며 당신은 사용해야합니다Object.prototype.hasOwnProperty.call(obj, key)
Bergi

2
예, 귀찮게하지 않는 것이 가장 좋은 방법이라고 생각합니다. 열거 할 가치가있는 모든 객체 (예 : 키-값-맵)가 열거 가능한 상속 속성을 갖지 않도록 신뢰해야합니다. (물론 배열을 열거하지 마십시오 ). 다른 것을 열거하는 드문 경우가 있고 귀찮다면 적어도 call. 권장하는 모든 규칙 obj.hasOwnProperties(key)은 그들이 무엇을하고 있는지 전혀 모르는 것처럼 보입니다.
Bergi

3
변환하기 Object로하는 것은 Map비용이 많이 드는 작업이며, 영업 이익은 특별히 중간체없이 해결책을 요구했다. 그렇다면 이것이 예외적 인 대답이 아닌 이유는 무엇입니까? 글쎄요,이 질문은 아마도 쓸데없는 일입니다.

1
@tmvnty 유형의 철자가 필요할 수 있습니다 function* entries<T>(obj: T): Generator<readonly [keyof T, T[keyof T]]> {…}. 또한 yield [key, obj[key]] as const;TypeScript가 배열이 아닌 튜플을 생성한다는 것을 깨닫는 데 도움이 될 것입니다.
Bergi

11

Nils의 답변은 객체를 맵으로 변환 하는 방법 을 설명 합니다. 그러나 OP는이 정보가 MDN 문서에서 어디에 있는지 궁금해했습니다. 원래 질문을 받았을 때는 없었을 수도 있지만 이제는 객체를지도변환이라는 제목 아래 Object.entries () 의 MDN 페이지에 있습니다.

객체를지도로 변환

new Map()생성자의 반복자를 받아 들인다 entries. 로 Object.entries쉽게 변환 할 수 있습니다 ObjectMap:

const obj = { foo: 'bar', baz: 42 }; 
const map = new Map(Object.entries(obj));
console.log(map); // Map { foo: "bar", baz: 42 }

7
const myMap = new Map(
    Object
        .keys(myObj)
        .map(
            key => [key, myObj[key]]
        )
)

1
@Ohar와 @TJCrowder의 솔루션 융합 : var buildMap2 = o => new Map(Object.keys(o).map(k => [k, o[k]]));.
7vujy0f0hy 2011 년

감사합니다. 객체 키도 정렬해야했기 때문입니다!
scottwernervt


1

ES6

객체를지도로 변환 :

const objToMap = (o) => new Map(Object.entries(o));

지도를 객체로 변환 :

const mapToObj = (m) => [...m].reduce( (o,v)=>{ o[v[0]] = v[1]; return o; },{} )

참고 : mapToObj 함수는 맵 키가 문자열이라고 가정합니다 (그렇지 않으면 실패 함).


-1

일부 JQuery의 도움으로

const myMap = new Map();
$.each( obj, function( key, value ) {
myMap[key] = value;
});

4
2019 년에는 문제를 해결하기 위해 jquery를 찾지 않아야한다고 생각합니다.
illcrx

jQuery는 여전히 많은 프로젝트에 있으며 이것은 나쁜 대답이 아니며 최적이 아닙니다.
보트 코더
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.