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.