简体   繁体   中英

How to convert a plain object into an ES6 Map?

For some reason I can't find this simple thing in the MDN docs (maybe I'm just missing it).

I expected this to work:

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

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

...but the first line throws TypeError: (var)[Symbol.iterator] is not a function

How do I make a Map from a plain object? Do I really have to first convert it into an array of arrays of key-value pairs?

Yes, the Map constructor takes an array of key-value pairs.

Object.entries is a new Object static method available in ES2017 (19.1.2.5) .

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

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

It's currently implemented in Firefox 46+ and Edge 14+ and newer versions of Chrome

If you need to support older environments and transpilation is not an option for you, use a polyfill, such as the one recommended by georg:

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

Please see nils' answer using Object.entries and/or bergi's answer using a generator function . Although Object.entries wasn't in the spec yet when the question was asked, it was at Stage 4 , so safe to polyfill and use on even back in April 2016 (just). (More on the stages here .) And generator functions were in ES2015. The OP specifically asked to avoid intermediaries, and while the generator doesn't completely avoid that, it does a better job than the below or (slightly) Object.enties .

FWIW, using Object.entries :

  • Creates an array of [name, value] arrays to pass to new Map
  • The Map constructor calls a function on the array to get an iterator; the array creates and returns an array interator object.
  • The Map constructor uses that iterator object to get the entries (the [name, value] arrays) and build the map

Using the generator:

  • Creates a generator object as a result of calling the generator function
  • The Map constructor calls a function on that generator object to get an iterator from it; the generator object returns itself
  • The Map constructor uses the generator object (as an iterator) to get the entries (the [name, value] arrays) and build the map

So: One fewer intermediary (the array from Object.entries ).

However, using Object.entries is simpler and creating that array isn't an issue 99.999% of the time. So really, either one. But they're both better than the below. :-)


Original answer:

To initialize a Map , you can use any iterator that returns key/value pairs as arrays, such as an array of arrays:

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

There's no built-in conversion from object to map, but it's easily done with Object.keys :

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

You can, of course, give yourself a worker function to handle that:

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

Then

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

Or here's a more l33t-looking (is that still a thing?) version:

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

(Yes, Map#set returns the map reference. Some would argue this is an abusage of reduce .)

Or we can really go over-the-top on obscurity:

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

No, I would never do that for real. :-)

Do I really have to first convert it into an array of arrays of key-value pairs?

No, an iterator of key-value pair arrays is enough. You can use the following to avoid creating the intermediate array:

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

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

The answer by Nils describes how to convert objects to maps, which I found very useful. However, the OP was also wondering where this information is in the MDN docs. While it may not have been there when the question was originally asked, it is now on the MDN page for Object.entries() under the heading Converting an Object to a Map which states:

Converting an Object to a Map

The new Map() constructor accepts an iterable of entries . With Object.entries , you can easily convert from Object to Map :

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

ES6

convert object to map:

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

convert map to object:

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

Note: the mapToObj function assumes map keys are strings (will fail otherwise)

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

Alternatively you can use the lodash toPairs method:

const _ = require('lodash');
const map = new Map(_.toPairs({foo: 'bar'}));

With the help of some JQuery,

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM