6

There's a question here which is similar but is specific to "when keys are unknown at runtime".

The MDN docs for Map state:

Use maps over objects when keys are unknown until run time, and when all keys are the same type and all values are the same type.

Use objects when there is logic that operates on individual elements.

I understand the advice about using maps "when keys are unknown until run time".

I'm confused by the line "when all keys are the same type and all values are the same type". What are they trying to suggest there? I mean, if all my keys are not of the same type, am I not forced to use Map anyway as it supports keys of different types? Also, why should the types of the values determine whether I use a Map or Object?

Also, I don't really understand "Use objects when there is logic that operates on individual elements." Could someone give me an example of what they mean by that?

Community
  • 1
  • 1
user5325596
  • 2,310
  • 4
  • 25
  • 42
  • 1
    Collections of data are usually homogenous. You wouldn't add users and books to the same map for example. – Felix Kling Oct 28 '15 at 13:15
  • 1
    I think the last paragraph from my post there answers your question well. Do you want me to expand on that? – Bergi Oct 28 '15 at 13:36

1 Answers1

5

Collections are typically homogenous. You've got a mapping from strings to numbers, from ids to objects, from usernames to User instances. All the keys have the same type, and all the value have the same type. You may select any of them for a task.

If you've got different types, you probably meant it a common "superclass" of them (in extreme, you may want ObjectObject). If you didn't, that's a code smell, and likely a mistake. Especially when you have keys of different types.

In contrast, objects are meant to be used as records: a combination of fields, of fixed size. Their members are denoted by identifiers, each of them may have a different type. They are properties in JavaScript, keyed by strings or symbols. You refer to them individually, and use them for distinct purposes.


Let's see some examples.

year → 2015
month → 9
day → 28

Yes, all keys are strings and all values are numbers. But we definitely don't expect to get any more or fewer of them. We use a record:

var date = {
    year: 2015,
    month: 9,
    day: 28
}
format → "MM/DD/YYY"
monthnames → ["January", "February", …]

Clearly, different value types. And we will use them individually. So again, an object:

var locale_en = {
    format: "MM/DD/YYY",
    monthnames: ["January", "February", …]
};
en → locale_en
de → locale_de
fr → locale_fr
…

This is clearly a different one. Notice the ellipsis? There could be more. And all keys are language codes, and all values are locales. When using them, we'll just use one of many. This is a collection:

var locales = new Map([
    ["en", locale_en],
    ["de", locale_de],
    …
]);
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • This, and @FelixKing's comment above is helping. So, if I understand correctly, mdn is saying "if the keys are of the same type, and the values are of the same type, and the key-value pairs represent the same 'thing'", then you should use `Map`. – user5325596 Oct 28 '15 at 14:03
  • Could you expand on "If you've got different types, you probably meant it a common "superclass" of them (in extreme, you may want Object->Object). If you didn't, that's a code smell, and likely a mistake. Especially when you have keys of different types."? Do you have an example, no matter how contrived? Your examples so far are very useful. – user5325596 Oct 28 '15 at 14:04
  • @user5325596: MDN is saying "*When you want a collection (with dynamic addition, removal, lookup and everything else), use `Map`*". The types of your keys and value are only hints. – Bergi Oct 28 '15 at 14:06
  • @user5325596: Felix had a good example. Take a collection that maps names to users and books. Uh, what? Exactly, two different types, that have nothing to do with each other. Either you want to separate collections (names to users, and titles to book), you really meant it (but it's actually more like "names to things", where things includes books, users, and maybe more), or you actually want a record: `var download = {user: xy, title: book}` with actually single fields. – Bergi Oct 28 '15 at 14:10
  • I get that having different types in the sense of "books", "users" etc in a collection is likely a code smell. I thought you meant having a collection where the keys had different types e.g `string`, `object`, `function`. Would you have an example where a collection could have keys of different types in that sense? And especially where the key is of type `function`. – user5325596 Oct 28 '15 at 14:15
  • @user5325596: That is just as unlikely, if you're not right away implementing a `Map` polyfill where you don't know what kind of keys your users will put. But in an application, it just makes no sense. That's more than a smell. – Bergi Oct 28 '15 at 14:20
  • 1
    "in an application, it just makes no sense" - aha, the penny drops, just because you can have keys of different types in a `Map`, doesn't mean you will, and you probably really shouldn't. Thanks for the explanations. Very helpful. – user5325596 Oct 28 '15 at 14:29
  • @user5325596: I've also [updated MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map$compare?locale=en-US&to=941721&from=932505). Better now? – Bergi Oct 28 '15 at 14:49
  • Looks better alright but there are a few typos. Not sure this is the right place to point them out though? – user5325596 Oct 28 '15 at 15:00
  • Let see after them [in chat](http://chat.stackoverflow.com/rooms/93600/discussion-between-bergi-and-user5325596). – Bergi Oct 28 '15 at 15:06