Collections in JavaScript

A collection is usually defined as a group of multiple elements that can be manipulated as a single unit. The following types of JavaScript collections are implemented in modern browsers at present:

  • Set - an unordered collection that cannot have duplicate elements;
  • Map - a collection that maps keys to values; a Map cannot contain duplicate keys, though its values are not unique;
  • WeakSet storing weakly held objects in a collection;
  • WeakMap with weak references to its keys; the keys of a WeakMap are objects and the values are arbitrary; both WeakSet and WeakMap are not protected from a garbage collector.
JavaScript Set Object

The default constructor of the Set does not require any arguments and returns an empty collection. The add() method invocation fills a Set object with values. The size property indicates the number of elements in a Set (or its cardinality):

var servers=new Set(); // default constructor
console.log(servers.size); // 0
servers.add("Apache HTTP Server"); servers.add("lighttpd"); servers.add("nginx");
console.log(servers.size); // 3

A Set can be built directly from an iterable object:

var jservers=new Set(["Glassfish", "Jetty", "Tomcat"]);
console.log(jservers.size); // 3

The has() method checks the existence of an element in the Set:

console.log(servers.has("nginx")); // true

An element can be removed from the Set with the help of the delete() method. Calling the clear() method will remove all values:

servers.delete("lighttpd");
console.log(servers.size); // 2
servers.clear();
console.log(servers.size); // 0

The forEach() method enables iteration through the elements of a Set. The method accepts a callback function as its mandatory argument. The function is called for each element of a collection:

var archiveFormats=new Set();
archiveFormats.add("bzip2"); archiveFormats.add("gzip"); archiveFormats.add("tar");
archiveFormats.forEach(
 function(value) { // callback function for Set has a single argument
  console.log(value);
 }
);

The forEach() method can have an optional parameter that will be referred to as this within the scope of the callback function:

var frameworks=new Set();
frameworks.add("CakePHP"); frameworks.add("Django"); frameworks.add("web2py");
var decoration="underline";
frameworks.forEach(
 function(value) {
  var div=document.createElement("div");
  div.style.textDecoration=this;
  div.textContent=value;
  document.body.appendChild(div);
 },
 decoration
);

Calling entries(), keys() or values() methods creates a Set Iterator:

var cmd=new Set();
cmd.add("ls"); cmd.add("netstat"); cmd.add("ps");
var entries=cmd.entries(); // Set Iterator
for(var i=0; i < cmd.size; i++) {
 console.log(entries.next().value[0]); // or entries.next().value[1]
}

If the browser supports the for ... of statement, the values could be retrieved from the Set above without a counter variable:

for(var [key, value] of entries) {
 console.log(value);
}

The keys() and values() methods work in the similar fashion:

var values=cmd.values();
for(var value of values) {
 console.log(value);
}

JavaScript Map Object

A no-arguments constructor creates an empty Map:

var map=new Map(); // default constructor creating an empty Map
map.set("key", "value"); // each key maps to at most one value
map.set("_key", "value");
map.set("key_", "value");
console.log(map.size); // 3
var value=map.get("key"); // extracting the value by the key
console.log(value);
console.log(map.get("fake")); // undefined: no value is associated with the supplied key

The advanced constructor builds a collection from an iterable object with key/value arrays:

var map=new Map([["browser", navigator], ["context", window], ["screen", screen]]);
console.log(map.size); // 3
console.log(map.get("screen").availHeight);

Checking the existence of a key is performed by calling the has() method. Procedures of deleting Map items are similar to methods exposed in the Set API:

if(map.has("_key")) {
 map.delete("_key");
 console.log(map.size);// Map size is 2 now
}
map.clear(); // Map size is 0

Map iteration is based on the forEach() method:

var acronyms=new Map();
acronyms.set("ACL", "Access Control List");
acronyms.set("CRL", "Certificate Revocation List");
acronyms.set("PRF", "Pseudo-Random Function");
acronyms.forEach(
 function(value, key) { // callback function for Map has two arguments
  console.log(key+": "+value);
 }
);

The code execution will display the following output:

ACL: Access Control List
CRL: Certificate Revocation List
PRF: Pseudo-Random Function

If the list of arguments of the forEach() method has two items, the second argument is utilized as this:

var description="Opera Mini Header";
var headers=new Map();
headers.set("X-OperaMini-Phone", "Android #");
headers.set("X-OperaMini-Features", "advanced, httpping, routing, file_system, folding, touch, viewport, camera");
. . .
headers.forEach(
 function(value, key) {
  console.log(this.toString());
  console.log(key+": "+value);
 },
 description
);

Each line of the output containing a key/value pair will have the Opera Mini Header "caption":

Opera Mini Header
X-OperaMini-Features: advanced, httpping, routing, file_system, folding, touch, viewport, camera
. . .

In addition, the code using Map objects can rest upon the entries(), keys() and values methods similar to the methods in the Set API:

// using entries() method
for(var [key, value] of acronyms.entries()) {
 console.log(key+": "+value);
}
// using keys() method to produce the same output
for(var key of acronyms.keys()) {
 console.log(key+": "+acronyms.get(key));
}

Let's summarize. Brief analysis of built-in JavaScript collections highlights the following traits of the new interfaces:

  • JavaScript collections are modifiable: they support both insertion and removal operations;
  • client-side collections are implemented as variable-size objects: the number of their elements can be changed programmatically; the changes are monitored;
  • collections support both random and sequential access to their elements; a Map is a random access collection: knowing a key provides access to the corresponding value; a Set iteration is sequential: it is based on the insertion order of its elements.