Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
ES6 Maps are now on by default in Chrome 38 (programming.com)
36 points by viach on Aug 8, 2014 | hide | past | favorite | 51 comments


It's also in Firefox (since Firefox 13). Documentation: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...


Or the original tweet rather than this weird scraping site: https://twitter.com/addyosmani/status/497441756708098048


Using objects as a map always bothers me, for instance, someone decides their username should be __proto__, and you end up with broken code:

    var map = { "__proto__": 1, "a":2 ,"b":3 };
    for (var key in map) if(map.hasOwnProperty(key)) {
       console.log(map[key]); 
    }


That looks like a cumbersome way to define a map, like small arrays within arrays.


It's an array of (key, value) pairs. The Map constructor takes an iterable of pairs.


It's probably to get around the non-deterministic ordering of objects.

New Map({'a': 'bar', '1': 'foo'});

Would flip the order of the keys.


To be pedantic, in all modern browsers the order is deterministic. But it certainly can be surprising.

For those who aren't aware, browser Javascript maintains insertion order, except for numeric keys, which are in numeric order ahead of all other keys.


Do you have a source on this by chance?


Hummm

My bet is that the Map() is turning an array of arrays into a map. And that in the future it will convert the original syntax into a Map as well


The syntax they have there is creating an array of arrays, and then passing that to the Map constructor, like you suspect. But it wouldn't be possible to make that syntax produce a Map directly -- if it did, how would you produce an array of arrays?

EDIT: My mistake, I misunderstood what you were saying.


It's easy to do with a helper function. For example, this works:

var objectToMap = x => new Map(Object.keys(x).map(o => [o, x[o]]));


By original syntax I meant Map({a:1, b:2})

Yes, I wouldn't want to change the syntax for array of arrays.


You never had to use `hasOwnProperty()` to iterate a map. `Object.keys()` in conjunction with `Array.prototype.forEach()` works well for this. Example:

var map = {a: '1', b: '2'}

Object.keys(map).forEach(function(k) { console.log(map[k]) })


To be fair `Object.keys()` is relatively recent and still needs to be shimmed for IE < 9. Even so I'd expect the new iterator based (like generators) key, value, and entry iteration to eventually outperform the `Object.keys()` interface that needs to return an array simply to have something to iterate over.


True. But anyone supporting IE < 9 I'd think would be using ES5 shim: https://github.com/es-shims/es5-shim But maybe not?



Practically a net neutral time saved in typing at the cost of readability of the object literal. I don't think there will be many cases where I'll be using Map over an Object literal.


Maps have quite a few advantages over bare objects:

* they have a length

* their keys are typed, not limited to strings. Objects as keys actually works

* they can be cleared in a single call

* they can easily be iterated over keys, values or (key, value) pairs


Still, I'd like if Map worked with values

    m = new Map([[new String(1), 1]])
    > Map { "1": 1 }
    m.get("1")
    > undefined


I'm not sure what you'd want here, you specifically allocated a string object and since JS has no notion of object equality it can only use identity.


You can still iterate through all the properties of an object (the indexes associated to the code units, in case of a String) and recursively implement equality on them this way.

The fact that, up to ES5, there's been no agreement on which name to use for the equality function and no default implementation for it it's of no excuse to avoid the issue. It's their (the people who standardized it) Map type, and they should've been able to make it as useful as possible.


> You can still iterate through all the properties of an object and recursively implement equality on them this way.

Can't do that for a hashmap since the value can change (by mutating the object) the hash would have to change as well and the object would have to move around. Not a sane proposition.


It wouldn't be much different than in any other language, that can let you define a mutable hashable type that breaks the hashability/equality contracts needed by maps. Mutating things that you'd use as keys is a well known no-no, and value equality is the expected behavior among all the developers I know. So implementing this is certainly not any less sane than other tricky behaviours already present in javascript (think equality coercions) and it would give a behavior which makes real code simpler.

On top of that, the Map implementation could always call Object.freeze() on the keys that it receives


I've searched but can't find the answer... Do they maintain insertion order?


Yep. In the ES6 draft:

> forEach calls callbackfn once for each key/value pair present in the map object, in key insertion order.

https://people.mozilla.org/~jorendorff/es6-draft.html#sec-ma...


They do, which is why you have to give it an iterator.


This is just a contrived example. In this situation there are a small number of keys that are all known in advance, which is exactly what object literals are for. A map would be more appropriate in situations where you have a large number of keys that are built up at runtime. Similarly, it is the latter situation where the ability to enumerate is important.


Maybe you can monkey patch Object.prototype to include a toMap function? That way you get nice literals and the benefits of maps.


Of course you could already use prototype-less objects as maps (Object.create(null))


You are still forced to use strings as keys with object hashes.

Maps allows object keys, which could be really handy in many situations.


Absolutely, that was a comment on the title more than on ES6 maps (which are great news, and have plenty of "map" features which ES objects don't provide: https://news.ycombinator.com/item?id=8152850)


Goodbye object literals too, apparently.


The intention is not to replace all 'map-like' uses of Object with Map. This MDN link explains clearly I think: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...


Thank you. Here is the advice from that page: 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.

Scroll down a bit and their first example is a Map with one string key, one object key and one function key...

I understand that Objects can only have keys that can be represented as a string. I do not understand why they say to use a Map when all keys are the same type and all values are the same type. Also, how would "logic that operates on individual elements" differ between a Map and an Object?


> I do not understand why they say to use a Map when all keys are the same type and all values are the same type. Also, how would "logic that operates on individual elements" differ between a Map and an Object?

An object is for describing the different properties of one thing. For example:

    var myCar = {
        make:   "Nissan",
        model:  "Altima",
        colour: "Black"
    };
See how each value is a different type of data (even though technically they are all strings)? Here, it would make no sense to enumerate over each property because they all have different meanings. Rather, you would use them individually based on what information you needed. On the other hand, a map is for describing a single property for many things:

    var manufacturers = new Map([
        ["Altima", "Nissan"],
        ["Acura",  "Nissan"],
        ["Accord", "Honda"],
        ["Camry",  "Toyota"]
    ]);
Here, each key and each value are all the same type of data as one another (models and makes, respectively). Because of that, it would make sense to have the structure be enumerable. Similarly unlike an object, it wouldn't make sense to assume that a particular known key exists, e.g. with hardcoded references to certain keys.


I can potentially imagine a helper function like `mapFromObject`, but yeah I agree with you. That syntax is disheartening. Enough to make me want to keep using `hasOwnProperty`.


Someone asked for this elsewhere, it's really simple. Kinda odd that it's not in the standard, though. EDIT: It's because Maps preserve insertion order, so the standard doesn't advocate use like this.

var objectToMap = x => new Map(Object.keys(x).map(o => [o, x[o]]));


The map constructor simply takes an iterable.


Why do you need to use .hasOwnProperty anyway?

    var map = {
        a: 1,
        b: 2,
        c: 3
    }

    for (var key in map) {
        console.log(map[key]);
    }
outputs

    1
    2
    3
in the console, like I expect.


Try running this:

    Object.prototype.d = 4;
Now you'll get:

    1
    2
    3
    4


If I were to run the code

    Object.prototype.d = 4;
I'd be asking for trouble.


I agree, but lots of JS developers (mistakenly) think there is nothing wrong with this:

    Object.prototype.myDumbShim = function () { ... };
Chances are good that your code will be running in the same scope as one of these people's code eventually.


There are many cases where this won't work.


Such as?

There are cross-browser issues with Map as well.


Look at the other comments. ES6 Map can be properly shimmed for the last 14 years of browsers.


I'm not sure why you were downvoted. Yes we all understand JavaScript is prototype based and it's certainly possible for a malicious developer to muck with the prototype of your object. In the real world when you have control over the object in question (which imho is the majority of cases) there's no need to call hasOwnProperty.


I agree that it was a good question which shouldn't have been downvoted. But I don't think malicious developers are the real concern in this situation. Rather, it is just a matter of defensive programming. By not using hasOwnProperty (or better yet, ES6 maps), you are creating code that could break just by including a new dependency in the project.


Thank you for your support in this difficult time.


In my programming, I have not built it in a way to prevent a malicious developer from changing object prototypes.

If there is actually an attack vector that gets closed by checking hasOwnProperty I'm interested.


Because of prototypical inheritance. If the object's prototype has properties, you may not want iterate those. Where as `key in map` will and `hasOwnProperty()` will only return true on those properties on the object.


Generally I want to look at properties from the prototype chain too.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: