A JavaScript Implementation of java.util.Map

As a Java developer, I use a lot of maps – especially instances of HashMap. A map is a dictionary or lookup table that contains key/value pairs. It provides a very convenient way to cache objects for easy retrieval by some identifier such as a string (the key). It’s so convenient, in fact, that I find myself struggling without a JavaScript equivalent, so I wrote one. Following is a partial JavaScript implementation of the java.util.Map interface, which you are free to copy and use.

JavaScript Map usage example

As you can see from the example below, using this map is just like using a map in Java.

var myMap = new Map(); myMap.put('myKey1',"Hello World!"); myMap.put('myKey2',{'prop1':'How','prop2':' are you?'}); console.log( myMap.get('myKey1') ); console.log( myMap.get('myKey2').prop1 + myMap.get('myKey2').prop2);</code></deckgo-highlight-code> <h2>JavaScript Map</h2> <deckgo-highlight-code language="javascript"><code slot="code">/** * An object that maps keys to values. A map cannot contain duplicate keys; each key can map to at most one value. * For those familiar with the Java programming language, this is similar to a HashMap; it implements most of the * methods defined by Java's java.util.Map interface. * * @constructor * @version 1.1.0 * @author cody@base22.com Burleson, Cody */ function Map() { this.dict = {}; /** * Returns the number of key-value mappings in this map. * @method */ this.size = function() { return Object.keys(this.dict).length; }; /** * Returns true if this map contains no key-value mappings. * @method */ this.isEmpty = function() { return Object.keys(this.dict).length == 0; }; /** * Returns the value to which the specified key is mapped, or null if this map contains no mapping for the key. * @method */ this.get = function(key){ return this.dict[key]; }; /** * Returns true if this map contains a mapping for the specified key. * @method */ this.containsKey = function(key){ if( this.get(key) !== undefined) { return true; } else { return false; } }; /** * Associates the specified value with the specified key in this map. If the map previously contained a mapping for the key, the old value is replaced. * @method */ this.put = function(key,value) { this.dict[key] = value; }; /** * Removes the mapping for the specified key from this map if present. * @method */ this.remove = function(key) { 'use strict'; delete this.dict[key]; }; /** * Removes all of the mappings from this map. The map will be empty after this call returns. * @method */ this.clear = function(){ this.dict = {}; }; /** * Executes the given callback for each entry in this map until all entries have been processed. * The given callback will be passed a map entry as parameter. So, for example... * * function myCallback(mapEntryItem) { * console.log('I will process this item: ' + mapEntryItem.text); * } * * myMap.forEach(myCallback); * * @method */ this.forEach = function(callback) { var len = this.size(); for (i = 0; i < len; i++) { var item = this.get( Object.keys(this.dict)[i] ); callback(item); } } }

Test Class

/** * ============================= * Map Test Cases * ============================= */ /** * Useful for unit testing JavaScript, this method asserts that the given condition is true. * If the given condition is not true, an optionally provided message is logged or 'Assertion failed.' * @method */ function assert(condition, message) { if (!condition) { console.error(message) || console.error('Assertion failed'); } else { console.log("-- PASS"); } } // Instantiate a new Dictionary object... var myMap = new Map(); // Test that isEmpty returns true at this point assert( myMap.isEmpty() ); // Test that size is zero at this point assert( myMap.size() == 0 , "size should be zero before any entries have been put into the lookup table."); // Put a sim0le string value in the dictionary and then test for it myMap.put('key1','http://value1?dt=2014_06_01&dummy=true'); // Now let's test adding a different kind of object... var testObj = {prop1:"Hello", prop2:" World!"}; myMap.put('key2',testObj); // Test that size now equals one assert( myMap.size() == 2, "size should be 2 after adding 2 entries."); var ref = myMap.get('key2'); // Test that ref was fetched from the dictionary assert( ref !== undefined , "ref should not be undefined; it should be a reference to testObj"); // Test a property of the fetched object; just to show there is support for more than just string types assert( ref.prop1 == 'Hello' , "ref.prop1 should equal 'hello' "); // Show that containsKey is false when there is no matching key assert( myMap.containsKey('notReal') == false, "containsKey('notReal') should return false; no such object is in the lookup table."); // Show that containsKey is true when there is a matching object found assert( myMap.containsKey('key2') == true, "containsKey('key2') should return true; that object is in the lookup table."); // Now, we remove an item to test the remove() method myMap.remove('key1'); assert( myMap.size() == 1 , "size should be 1 after removing item under 'key1'."); // Finally, test the clear() myMap.clear(); assert( myMap.size() == 0 , "size should be 0 after clearing lookup table.");

JavaScript Map API

Map

new Map()

An object that maps keys to values. A map cannot contain duplicate keys; each key can map to at most one value. For those familiar with the Java programming language, this is similar to a HashMap; it implements most of the methods defined by Java’s java.util.Map interface.

Methods

clear()

Removes all of the mappings from this map. The map will be empty after this call returns.

containsKey(key)

Returns true if this map contains a mapping for the specified key. Parameters:

Name Type Description
key String key whose presence in this map is to be tested

forEach(callback)

Executes the given callback for each entry in this map until all entries have been processed. The given callback will be passed a map entry as parameter. So, for example…

function myCallback(mapEntryItem) { console.log('I will process this item: ' + mapEntryItem.text); } myMap.forEach(myCallback);

Parameters:

Name Type Description
callback function The callback function that will be called for each entry in the map and which will be passed the value for each entry in the map.

isEmpty()

Returns true if this map contains no key-value mappings.

put(key, value)

Associates the specified value with the specified key in this map. If the map previously contained a mapping for the key, the old value is replaced.

Name Type Description
key String key with which the specified value is to be associated
value Object value to be associated with the specified key

remove(key)

Removes the mapping for the specified key from this map if present.

Name Type Description
key String key whose mapping is to be removed from the map

size()

Returns the number of key-value mappings in this map.

Gist on GitHub

https://gist.github.com/codyburleson/089157ed8eca114da8c4#file-javascript-map