266

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?

1
  • 4
    FWIW, it may be worth switching your accepted answer from mine to nils' or bergi's. Object.entries really is the better approach over Object.keys, and bergi's generator function approach is slightly more direct than either Object.keys or Object.entries. Commented Jul 11, 2018 at 12:30

6 Answers 6

382

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]]);
9
  • 4
    A "polyfill" will be rather trivial: Object.entries = obj => Object.keys(obj).map(k => [k, obj[k]])
    – georg
    Commented Apr 15, 2016 at 10:29
  • 4
    Object.entries landed in Node 7.x proper (without a flag) btw
    – Lee Benson
    Commented Nov 15, 2016 at 9:03
  • 2
    Not only is Object.entries in Node7, it is also part of the ES2017 final specification. Thus, this should be the accepted answer, IMO Commented Sep 18, 2017 at 22:13
  • 1
    @AnilRedshift - Well, this or the generator function answer, since the OP asked for a solution avoiding intermediaries. Commented Jul 11, 2018 at 12:43
  • 2
    Unfortunately, it will not. Commented Feb 5, 2019 at 13:43
39

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'
9
  • Nice example - just a note to others, you might want to do a if(!obj.hasOwnProperties(key)) continue; right after the for loop condition to ensure that you do not yield properties inherited from the object prototype (unless you trust the object, but should do this anyways when iterating objects using in as a good habit).
    – puiu
    Commented Mar 2, 2017 at 20:16
  • 6
    @Puiu No, you should not, and it's a bad habit. If you don't trust the object, you must not trust its .hasOwnProperty property as well, and you'd have to use Object.prototype.hasOwnProperty.call(obj, key)
    – Bergi
    Commented Mar 2, 2017 at 20:26
  • 5
    Yes, I think not bothering is the best practice. You should trust all the objects that are worth enumerating (i.e. key-value-maps) to not have any enumerable inherited properties. (And yes of course avoid enumerating arrays). If you have a rare case of enumerating something else, and you bother, you should at least do it properly with call. All the conventions out there that recommend obj.hasOwnProperties(key) appear to have no idea what they are doing.
    – Bergi
    Commented Mar 2, 2017 at 20:50
  • 5
    Converting an Object into a Map is an expensive operation and the OP specifically asked for a solution without intermediates. So why isn't this the excepted answer? Well, asking this is probably futile, it just annoys me.
    – user6445533
    Commented Oct 6, 2017 at 13:22
  • 1
    @tmvnty You might need to spell out the type function* entries<T>(obj: T): Generator<readonly [keyof T, T[keyof T]]> {…}. Also yield [key, obj[key]] as const; would help TypeScript realise that it's yielding tuples, not arrays.
    – Bergi
    Commented Aug 4, 2020 at 23:49
29

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

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)

1
  • 5
    You can do the following to convert the map back to an object: Object.fromEntries(map.entries()) Commented Mar 16, 2022 at 21:23
9
const myMap = new Map(
    Object
        .keys(myObj)
        .map(
            key => [key, myObj[key]]
        )
)
2
  • 3
    Fusion of @Ohar's and @TJCrowder's solutions: var buildMap2 = o => new Map(Object.keys(o).map(k => [k, o[k]]));.
    – 7vujy0f0hy
    Commented Mar 12, 2017 at 11:42
  • 1
    Thanks, as I needed to sort the object keys too! Commented Dec 5, 2019 at 16:02
4

Alternatively you can use the lodash toPairs method:

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.