Friday, October 16, 2015

JavaScript Collections - Map

I still can't fold them back up!
Ready to be confused? Okay, so you know that JavaScript has a map function on Array objects. It creates a new Array by applying a given function to each element of the Array. But now it also has a Map collection object. Now when you talk about a Map in JavaScript, are you talking about a function on an Array or a key/value pair data structure?

Those of us who did a lot of programming in other languages before JavaScript are probably familiar with classic data structures like the Map. A Map is a (typically) indexed collection of keys and their associated values. If you know the key, you can grab the value. C++ has collections objects, as does Java. JavaScript has not had a native Map until recently, but I've never really missed it. Why? Keep reading.

In many of the newest browsers and in Node 4, we can now use Maps. Their functionality should come as no surprise to anyone familiar with basic data structures found in other languages.

var m = new Map();

m.set("key1", "value1");
m.set("key2", "value2");

console.log(m.size); // 2

console.log(m.get("key1")); // "value1"
console.log(m.get("key3")); // undefined
console.log(m.has("key2")); // true
console.log(m.has("key4")); // false

But this is JavaScript! We needn't limit ourselves to just one type of key or value! Check this out:

var p = new Map();

// function as a value...not too strange:

p.set("f1", function(x) { return x*42; });

console.log(p.get("f1")(2)); // 84

// function as a key...a bit odd:

var w = function(z) {
    return z % 3;
};

p.set(w, "weird");

console.log(p.has(w)); // true
console.log(p.get(w)); // weird

Sure, it's perfectly legal code...but why? I know I'm not the world's smartest software engineer, but I cannot think of an example where putting a function as the key in a Map would make any sense. If you can think of one, please comment below.

Now we're having fun with Maps and we're all excited about JavaScript getting this great new data structure. But this is not a whole lot different from what we could always do in JavaScript with objects, since objects behave pretty much like Maps.

var h = {};

h["key1"] = "value1";
h["key2"] = "value2";
h["func1"] = function(t) { return t / 8; };

console.log(h["key1"]);      // value1
console.log(h["key3"]);      // undefined
console.log(h["func1"](16)); // 2
console.log(h.func1(32));    // 4

See? Pretty much the same as my first Map example up at the top. Fine, plain Objects have no size field...so I suppose that's one thing that Maps offer. There are also some differences is how iteration is handled. Consider the following example:

var myMap = new Map();
myMap.set("k1", 33);
myMap.set("k3", 55);

var myObj = {};
myObj["k1"] = 33;
myObj["k3"] = 55;

for (e of myMap) {
    console.log(e);    // the key and value as an array
    console.log(e[0]); // just the key
    console.log(e[1]); // just the value
}

for (e in myObj) {
    console.log(e);        // just the key
    console.log(myObj[e]); // the value
}

Iterating over the Map with for (e of myMap) gives you values for e that are 2-element arrays containing both the key and the value for each Map entry. Iterating over the Object with for (e in myObj) gives you values of e that are just the key.

I'm not going to tell you that JavaScript Maps are the greatest thing since sliced bread, but maybe sliced bread was never that big of a deal anyway. It's not like people didn't have knives. And speaking of bread...

Amphibian.com comic for 16 October 2015