Week 11: JavaScript Collections
This reading draws from pages
by
John Davis
and
David Humphrey.
Table of Contents
This week we dive deeper into JavaScript. This reading has two main goals:
- learn how the browser makes sets of DOM elements available to us as JavaScript collections such as arrays
- learn how to work with JavaScript arrays, both individually and collectively with loops
A secondary goal of this reading is to take another look at JavaScript strings, which are collections, too, and which interact with arrays in some useful ways.
The section on arrays uses this file as a running example. Control-click on the link to download the source file, and have it ready to use and read later.
The DOM and Collections of Objects
Re-Introduction to the DOM
We have seen that the browser not only renders a web page for us to view. It also exposes the page to our JavaScript code as a hierarchy of objects:

head
and a body
consisting of a
div
and a script
element.
The
div
contains an image, a heading, a
paragraph, and another div
.
The Document Object Model (DOM) connects web pages to our scripts by representing the structure, content, and styling of a document. We access the DOM with JavaScript code.
The DOM tree is an object. The tree is a model of the web page where each element on the page is an object stored as a property in the tree.
In the example in the diagram above, the body is an object
that contains objects for the div
and the script
element. The div
contains objects for the image,
the heading, the paragraph, and another div
.
Each of those objects holds a representation of the corresponding HTML element:

img
object in the DOM is a model of the
HTML element in the web page, with all the same attributes
as the HTML.
Working with DOM Objects
An object is an abstraction of some entity we can describe or
talk about. It has data properties and methods. We access
an object's properties and methods using the .
notation, for example, aString.length
or
Math.sqrt()
. We can also change the value of
property using an assignment statement. An method is a
function we can call; it's a function that belongs to an
object and has access to its data properties.
Any function we create becomes part of the window
object that sits at the top of the DOM tree for a page. That
object also has built-in functions, including the
alert()
and prompt()
functions we've
used.
As we've seen, we can interact with the DOM in many ways:
-
We can access any element in the tree:
let element = document.querySelector("p");
-
We can access and modify an element's text content:
element.innerText = "new text";
-
... or its HTML content:
element.innerHTML = "new <em>text</em>";
-
We can access any attribute of an element using
getAttribute()
:let imgSource = element.getAttribute("src");
-
... and modify an attribute's value using
setAttribute()
:element.setAttribute("src", "newImage.jpg");
-
We can access an element's id or class attributes directly
as properties:
element.id element.className
-
Finally, we can access and modify an element's styling through
its
style
data property:element.style.background = "red";
Getting Collections of Objects from the DOM
Up to now, we have been limited to working with single values:
the first p
element in a document, or the only
class name associated with the element. We know, though, that
a document may have many p
elements, or
td
elements, or li
elements. We
also know that a class can have more than one class associated
with it.
The DOM exposes these features to us as a collection of objects. This collection takes the form of a JavaScript array. We can think of an array as a list of objects that we can access by their position.
Here are two ways to get a collection from the browser:
-
We can access all of the
p
elements in the tree using thequerySelectorAll()
method:let paragraphs = document.querySelectorAll("p");
The object returned byquerySelectorAll()
is a collection: a list of elements in the DOM that match the given selector. -
We can access all of an element's classes through its
classList
data property.let allClasses = element.classList;
TheclassList
property is also a collection.
We can interact with these collections in a number of ways: access individual items in the list, add items to the list, remove items for the list, and so on.
Let's learn more about JavaScript arrays so that we can interact with our web page in more useful ways.
JavaScript Arrays
A JavaScript array is a collection of objects. We can treat an array as a group, and we can access the members of the collection individually by their position in the list. Arrays have many useful properties and methods that we can use when working with lists in JavaScript.
Array Basics
As with other JavaScript data types, we can create an array
literal in our scripts. We use square brackets,
[...]
, to indicate an array:
❯ let hobbits = ["Merry", "Pippin", "Frodo"];
In this example, hobbits
is a collection
containing three elements:
❯ hobbits ["Merry", "Pippin", "Frodo"]
Like strings, arrays have a data property that stores the size of the collection:
❯ hobbits.length 3
We can access the objects in the array using the same square brackets. The items are numbered 0, 1, 2, ....
❯ hobbits[0] "Merry" ❯ hobbits[1] "Pippin" ❯ hobbits[2] "Frodo" ❯ hobbits[3] undefined
Note that hobbits[3]
is undefined. There are
only three items in the collection, and
hobbits[3]
refers to a fourth item.
We can also modify the objects in an array using an assignment statement:
❯ hobbits[1] = "Samwise Gamgee"; "Samwise Gamgee" ❯ hobbits ["Merry", "Samwise Gamgee", "Frodo"] ❯ hobbits.length 3
Now, hobbits[1]
contains the value
"Samwise Gamgee". The rest of the array, including its
length, are unchanged.
Receiving Collections from the DOM
Creating arrays in our code can sometimes be quite useful. It is much common, though, for us to work with arrays that we receive from the DOM.
Consider this web page. (Download it now you haven't already.)
We have been using the querySelector()
method to
retrieve an element from the DOM. But there are four
paragraphs in this document, and querySelector()
returns only the first of them.
The querySelectorAll()
method enables us to
retrieve a collection of all elements in a web page that match
the selector. For example:
❯ let allPs = document.querySelectorAll('p'); undefined ❯ allPs NodeList [<p>, <p>, <p id="handle">, <p>]
We can access individual elements in this collection using the same square brackets:
❯ allPs[0] <p>I'm a little teapot.</p> ❯ allPs[2] <p id="handle" class="blue border padding">Here is my handle.</p>
Another common way to receive a collection from the DOM is
to ask an element for a list of the classes defined on it.
Earlier, we saw that DOM elements have a
classList
data property. It is a collection:
❯ let specialP = allPs[2]; ❯ let classes = specialP.classList; ❯ classes.length 3 ❯ classes[0] "blue" ❯ classes[1] "border" ❯ classes[2] "padding"
We can work with collections of classes and collections of elements in the DOM using other features of JavaScript arrays.
Methods for Querying and Modifying Arrays
One of the common uses of JavaScript on a web page is to add
or change styling on an element. We can do so by adding a
class to the element's classList
or removing a
class from the list.
Suppose we wanted to add a blue background to the first
paragraph on the web page. We can use the array method
add()
:
❯ let allPs = document.querySelectorAll('p'); ❯ let firstP = allPs[0]; ❯ firstP.classList.add('blue');
To remove an element from an array, we use the method
remove()
:
❯ allPs[2].classList.remove('border');
These methods are a handy way for a script to change the styling on a web page.
Iterating Over the Items in a Collection
Sometimes, we would like to take some action on every element
in a collection. Last week, we learned that the
while
statement gives us a way to 'loop' over an
action. We can use a while
statement to take the
same action on each element in an array.
Recall the basic form of a while
statement that
loops over a sentinel variable
:
// initialize the sentinel variable while ( /* condition on variable is true */ ) { // take action // update sentinel variable }
For example:
let x = 0; while (x < 10) { console.log(x); x++; }
We can use a loop of the same form to loop over all the elements in a collection.
❯ let allPs = document.querySelectorAll('p'); ❯ let i = 0; ❯ while (i < allPs.length) { console.log(allPs[i].innerText); i++; } [Log] I'm a little teapot. [Log] Short and stout. [Log] Here is my handle. [Log] And here is my spout.
Notice the pattern: The sentinel variable is the variable we use to access items in the collection. It starts at 0, the location of the first element. The loop stops when the sentinel variable equals the size of the collection, because that value is past the last element in the collection.
We can also use a loop of this sort to modify all the elements in a collection. This loop adds a line number marker to the front of each paragraph in the poem:
❯ i = 0; ❯ while (i < allPs.length) { let element = allPs[i]; let text = element.innerText; let lineNumStr = '[line ' + i + '] '; element.innerText = lineNumStr + text; i++; }
Note, we have to reset i
to 0, because our
previous loop advanced it to 4 before stopping the loop!
Finally, suppose that we would like to add a blue background
to every element. We can use a loop to add the
blue
class to each element's class list:
❯ i = 0; ❯ while (i < allPs.length) { let element = allPs[i]; element.classList.add('blue'); i++; }
After writing so many while
statements to process
this list of elements, you may be wishing for a way to write
the loop that is not so prone to error. JavaScript has such
a statement, the for
statement, which we will
learn about in class this week.
If we are willing to put the action we want into a function,
we can also use the forEach()
method of the
array:
❯ function addBlue(element) { element.classList.add('blue'); } ❯ allPs.forEach(addBlue);
This can be the handiest of ways to process every element in a collection once you are comfortable writing JavaScript functions.
JavaScript Strings
We have been using JavaScript strings for a few weeks. Now that we know about how collections work in JavaScript, there are a few more features of strings that we can take advantage of — because strings are collections, too. They contain characters.
We can access the individual characters in a string using the square brackets:
❯ let name = 'Eugene'; ❯ name[3] "e"
Note that characters in JavaScript are strings of size 1.
Strings have a number of methods that are useful for working with text of elements in the DOM. Let's use this string:
❯ let sentence = 'The south wall warms me: November has begun,'; ❯ sentence "The south wall warms me: November has begun,"
... to consider some of them:
-
s.charAt(i)
works just likes[i]
, returning the character at position i.❯ sentence.charAt(15) "w"
-
s.includes(str)
returnstrue
if the string s contains the string str, andfalse
otherwise.❯ sentence.includes('warm') true ❯ sentence.includes('December') false
-
s.startsWith()
ands.endsWith()
are boolean methods that check to see if a string begins or ends with a particular string.❯ sentence.startsWith('warm') false ❯ sentence.startsWith('The') true ❯ sentence.endsWith('un,') true ❯ sentence.endsWith('begun') false
-
s.indexOf(str)
returns the position of the first occurrence of str in s, or -1 if it never occurs.❯ sentence.indexOf('with') -1 ❯ sentence.indexOf('warm') 15
-
s.toLowerCase()
ands.toUpperCase()
return a new string with all characters converted to lower case or upper case, respectively.❯ sentence.toLowerCase() "the south wall warms me: november has begun," ❯ sentence.toUpperCase() "THE SOUTH WALL WARMS ME: NOVEMBER HAS BEGUN,"
-
s.trim()
returns a new string with leading and trailing whitespace removed.❯ ' sloppy input with extra whitespace '.trim() "sloppy input with extra whitespace"
-
s.slice(i,j)
returns a new string consisting of the characters in s from position i up to position j.❯ sentence.slice(15,20) "warms"
Notice that these number work like the counters on our loops: position 15 is part of the slice, but position 20 is not. The length of the returned string is 20 - 15 = 5.
Finally, there is a connection between strings and arrays. We
can split a string at a separator using the split()
method. It returns an array of substrings that lie between the
separators. This may be easiest to understand by example:
❯ let data = 'Wallingford,Eugene,EBAR 022' ❯ let parts = data.split(','); ❯ parts ["Wallingford", "Eugene", "EBAR 022"]
Arrays have a method that reverses this process:
join(str)
creates a string by combining strings
for all of the array's elements, separated by str.
For example:
❯ parts[2] = 'EBAR 019'; "EBAR 019" ❯ parts.join(',') "Wallingford,Eugene,EBAR 019"
We can use any characters to split strings or join arrays. This can be very handy for processing spreadsheet files that we would like to turn into rows in a table or entries in a list.
Closing Credits
The string used as an example in the preceding section is a line from the poem There's Nothing Like the Sun by Edward Thomas.