Week 9: JavaScript Functions and the DOM
This reading draws from a page by
David Humphrey
and from the open textbook
Fundamentals of Web Programming.
What is JavaScript?
This week we dive deeper into the third language of web development, JavaScript. Along the way, we will also learn more about HTML and CSS, especially how they are exposed to web developers by the browser.
We have been calling HTML and CSS languages for describing the content and display of web pages. JavaScript is a programming language, which means that it opens up to you the full power of the web browser — and computer. Knowing JavaScript offers advantages over knowing only HTML and CSS, at the cost of some complexity.
This week we will learn about several new features of JavaScript. This reading has three sections:
- its extends our ability to access a web page with JavaScript, both the content (HTML) and the styling (CSS)
- it moves beyond running JavaScript in the console to including JavaScript code in a web page
- it introduces the idea of a function, an essential tool for creating web pages that support interaction with the user and the browser
This reading uses several small web pages to illustrate ideas. There are links to these pages throughout the reading. You can also download this zip file that contains all the HTML and JavaScript file for the reading and follow along in your editor.
Accessing a Web Page with JavaScript: HTML and CSS
To work through this section, open up this web page, accessing-dom.html, in a separate tab or window. If you'd like to see the HTML for the file as you read, download the file to your computer and open it in VS Code.
Accessing HTML Elements
Last week, we learned that we can use JavaScript's
querySelector()
method to access an element in
a web page by its HTML tag. For example, we can access the
page's h1
heading and inspect its HTML with:
let h1 = document.querySelector('h1'); h1.innerHTML
We can also modify its attributes using an assignment statement:
h1.innerText = 'I am a little blue today';
Both of these snippets of code use a variable and an assignment statement. The variable is a name for a value. Recall that an assignment statement works like this:
-
Evaluate the expression on the right side of the
=
(the assignment operator). - Make the name on the left side of the operator refer to the value that results from Step 1.
Our ability to interact with HTML using JavaScript is bigger than just access by tag, though. Here are three additions to our set of tools.
First, we can also access an element by its class or id:
let element = document.querySelector('#main-content'); element element.innerText = 'Here is my handle...';
This is a common use of JavaScript on a web page, especially with id's. They are unique and so allow us to target a specific element directly.
Second, there are several elements in a document that we can
access directly, without using querySelector()
.
Two are the head and the body. These
elements are required and unique, so the DOM exposes them to
us as data properties:
let headElement = document.head; headElement let bodyElement = document.body; bodyElement.innerHTML = '<h1>I am a little blue today</h1>';
Note that when we replace the innerHTML
of the
body, we overwrote the entire body, including the paragraph
element. If we only want to change the h1
element, we need to target it directly.
Finally, we can add a class to an element by changing its
className
property. For example:
bodyElement.className bodyElement.className = "myclass"; bodyElement.innerHTML = "<h1>Now I'm golden.</h1>";
Reload the playground web page before proceeding.
Accessing Style Attributes
In addition to accessing an element's content, we can also
access its styling. Every element has a
style
data property. It is an object that
contains all of the style information associated with the
element. For example:
let bodyElement = document.body; let bodyStyle = bodyElement.style; bodyStyle let h1 = document.querySelector('h1'); let h1Style = h1.style; h1Style
Don't worry for now about the style object itself, which looks different than the objects we have seen thus far. We will learn about that kind of object soon.
For now, know that once we have access to an element's styling information, we can modify a specific style attribute with an assignment statement. Try this:
h1Style.backgroundColor = "lightblue";
Note: We can also access object attributes
in succession without creating intermediate variables. For
example, this statement changes the body
's
background color without creating variables for the body or
its style attribute:
document.body.style.backgroundColor = "lightblue";
Putting all of our JavaScript knowledge together, we are able
to target an element for new content and styling, perhaps in
response to a user action. Here's a short sequence of JS
statements to modify the page's main
element:
myMain = document.querySelector('main'); myMain.innerHTML = "<h3>Where have all the flowers gone?<h3>"; myMain.style.height = "200px"; myMain.style.width = "200px"; myMain.style.backgroundColor = "lightgreen";
Taken together, these statements make a script, a short JavaScript program to perform a specific task. We can do more with code such as this than enter it into the console; we can also include it on our web pages for the browser to execute.
That is the topic of the next section.
Practice
Reload the page from this section in your browser. (If you would rather practice with one of your own web pages, feel free, just be aware that you may have to adjust the exercise a bit if your page has different classes and ids.)
- Change the background color of an element.
- Can you change the font size of an element to 48pt?
-
Experiment with other style elements you have learned about
in CSS. For example, see if you can change an element's
margin or make it disappear (
hidden
).
Using JavaScript on a Web Page
So far, all of our JavaScript code has been written in a stand-alone form, executed in our browser's console (or in node.js).
Our ultimate goal is to be able to run our JavaScript code within web pages. To do that, we need a way to include the code in an HTML file. HTML isn't anything like JavaScript, though, so we can't simply type our JavaScript code in the middle of an HTML file and expect the browser to understand it.
Instead, we need an HTML element that can contain, or link to,
our JavaScript code. HTML provides such an element:
script
.
When we learned CSS, we saw that we could include CSS code in
our web pages
in three different ways.
We can use the script
element to add JavaScript to
a web page in two different ways.
Inline Scripts
First, we can embed a JavaScript program directly as the
content of a script
element.
Consider
this web page,
with the same HTML content as in the previous section plus
this script
element containing the JavaScript
code from the end of of the section:
<script> myMain = document.querySelector('main'); myMain.innerHTML = "<h3>Where have all the flowers gone?<h3>"; myMain.style.height = "200px"; myMain.style.width = "200%"; myMain.style.backgroundColor = "lightgreen"; </script>
The browser loads the HTML from beginning to end, so it loads
in the head
, then the body
, and
finally the script
. When it loads the script,
it executes the JavaScript code, resulting in a new
main
section.
We can place internal scripts anywhere in an HTML file.
However, it is common to put them at or near the
end of the body
. That way,
the browser has loaded most or all of the HTML code before
it loads and executes the JavaScript. That is essential
in the case of our "myMain" script, because the code modifies
an existing element in the HTML.
Exercise:
Edit the inline-script.html
so that the script
appears in the head
element or at the top of the
body
. Now reload the page. What happens? Why?
We can have as many script
elements as we like in
an HTML file. This will be useful when we have more than one
form of user input, or when we want to use someone else's
JavaScript code into our page.
External Scripts Linked via URL
For small bits of code, inline scripts are fine. They can also be useful when we are experimenting with new ideas. However, as scripts get larger, embedding them directly within the HTML file becomes unwieldy.
Furthermore, like CSS, JavaScript has a different purpose than HTML. It is useful to separate JavaScript code from HTML code and to putthem into their own files for a number of reasons:
- The HTML becomes harder to read. Instead of looking at semantic content about the structure and content of a web page, we also have to read and understand programming logic. This can make it harder to understand the file, especially while debugging.
- VS Code handles HTML and JavaScript equally well, even when they appear in the same file. However, there are many tools for working with HTML, and even more tools for working with JavaScript, that work only when given code the proper type. For example, web developers often use tools for "bundling" JavaScript code that is used on a website. Those tools can't do their job if the JavaScript is embedded inside with HTML markup.
- Finally, browsers can cache files in order to improve the load time of a web site. When a large JavaScript file is embedded in an HTML file, the JavaScript code cannot be cached separately.
For these and other reasons, it is customary to move
JavaScript programs to separate files with a
.js
file extension. We then tell the browser
to load and execute these files using a different form of
the script
element:
<script src="script.js"></script>
Notice that, in this case, there is no content within the
script
element. Instead, the src
attribute specifies a path to the script file. This is
reminiscent of how the img
element works, though
script
needs a closing tag because it can
sometimes contain content.
With an external script, the browser begins by loading the
.html
file. When it encounters the
<script src="script.js">
element, it
loads the script.js
file from the web server,
and then runs the program it contains.
You can see this process at work in
this version
of the previous web page, with the JavaScript code now in
a separate .js file.
Notice that the script.js
file contains nothing
but JavaScript code, without the <script>
tags. This is the same code that we created in our
interactions with the web page within the browser's console.
External scripts do not have to reside on the same server as the web page. Like external images and third-party CSS style sheets, they can live on another server. To access them, we provide an absolute URL to the file.
Combining the Approaches
We can combine both of these methods, and include as many scripts as we need. The scripts we include can be:
- inline, embedded within the HTML file
- external, using a relative URL to a file on the same web server as the HTML file
- external, using an absolute URL to a file on another web server
For example, consider
three-scripts.html.
It loads
the same local external script.js
file
as before to modify the main
element on the page.
It also loads a remote external script that defines code for
converting plaintext diagrams into graphics. The third
script is an inline script that uses the code defined in the
remote script to create a diagram on the page.
This page illustrates a common pattern:
- loading an external script that defines objects, and then
- writing an internal script that uses those objects to do something on the page.
(By the way, the typograms.js
script is a cool
way to create graphics within web pages. For more
information, check out
the Typograms homepage
on Google's Github page.)
JavaScript Functions
Last week, we learned that we could use methods provided by JavaScript to compute values and take actions. For example:
❯ Math.sqrt(16) 4 ❯ let text = ' Eugene '; undefined ❯ text.trim() 'Eugene'; ❯ console.log('Area = 10'); [log] Area = 10 undefined
More recently, we have been using the
querySelector()
method to access information out
of elements in a web page.
"Method" is a word associated with objects in many programming
languages, including JavaScript. We can think of it as a
synonym for function, a word familiar to us
from our math courses. String.trim()
and
especially Math.sqrt()
even resemble the sort of
functions we saw in math courses: given a value as input, they
return a specific value as output.
We'll sometimes need to write our own functions. For example, we will need to tell the browser what to do when a user takes an action, such as pressing a button or clicking the mouse. We will do that by writing one or more JavaScript statements that the browser can invoke when the user takes the action. We will package our JavaScript statements as a function, which the browser will call in much the same way that we invoke a method.
At its simplest, a function is a sequence of JavaScript statements like the ones in the script we saw earlier in the reading. However, instead of thinking of that snippet of code as five separate statements, we think of it as a single unit. We might think of it as "modify the main section".
This is an abstraction: stepping back from a bunch of details and thinking of them as one thing. This may seem unfamiliar to us when we think about in the context of JavaScript, but we all use abstractions in everyday life without thinking about them much at all.
For example, you may tell your friend, "I'm going to Web Development now." This is an abstraction of many smaller actions taken in sequence, perhaps something like:
- Leave your dorm room.
- Walk down the halls and stairs, and out of the dorm.
- Walk across campus to the Physics building.
- Enter the building and wait for the elevator.
- Take the elevator to the third floor.
- Enter Room 314 and find your favorite place to sit.
You would have a lot of long, boring conversations if you responded with all six of those steps every time a friend asked you what you were doing. You might even lose a lot of friends!
Your friend understands those steps are necessary when you say you are going to class, so the two of you can communicate in terms of the abstraction. Note that some of those six steps can be broken down into several smaller steps each, which would make the conversations even more tedious.
Defining a function is how we create an abstraction in Javascript code. A function is a portion of code that can be called by some other code, in particular the web browser. Functions can take values as input and may return a value or take an action.
We will use JavaScript functions in two ways. First, we will give a name to a set of repeatable steps that we can call in different ways and from different places in our scripts. Second, we will use them to define actions that can be performed in response to events, whether initiated by the user or triggered by the browser. We will explore both of these uses in the coming weeks.
JavaScript functions have other uses in web programming, but they are beyond the scope of this course.
If you would like to see an example of a function definition
now, check out
this page,
which shows
the inline script
from the previous section changed to define a function named
modifyMain()
. The second script then calls the
function to carry out the actions.
Don't worry about the details of the function definition at this point. Defining functions is one of the main topic for class this week.