Begin to Code with JavaScript

Rob Miles

BEGIN TO CODE WITH JAVASCRIPT

Published with the authorization of Microsoft Corporation by:

Pearson Education, Inc.

Copyright © 2022 by Pearson Education, Inc.

All rights reserved. This publication is protected by copyright, and permission must be obtained from the publisher prior to any prohibited reproduction, storage in a retrieval system, or transmission in any form or by any means, electronic, mechanical, photocopying, recording, or likewise. For information regarding permissions, request forms, and the appropriate contacts within the Pearson Education Global Rights & Permissions Department, please visit www.pearson.com/permissions

No patent liability is assumed with respect to the use of the information contained herein. Although every precaution has been taken in the preparation of this book, the publisher and author assume no responsibility for errors or omissions. Nor is any liability assumed for damages resulting from the use of the information contained herein.

ISBN-13: 978-0-13-687072-2

ISBN-10: 0-13-687072-4

Library of Congress Control Number:  2021941656

ScoutAutomatedPrintCode

TRADEMARKS

Microsoft and the trademarks listed at http://www.microsoft.com on the “Trademarks” webpage are trademarks of the Microsoft group of companies. All other marks are property of their respective owners.

WARNING AND DISCLAIMER

Every effort has been made to make this book as complete and as accurate as possible, but no warranty or fitness is implied. The information provided is on an “as is” basis. The author, the publisher, and Microsoft Corporation shall have neither liability nor responsibility to any person or entity with respect to any loss or damages arising from the information contained in this book or from the use of the programs accompanying it.

SPECIAL SALES

For information about buying this title in bulk quantities, or for special sales opportunities (which may include electronic versions; custom cover designs; and content particular to your business, training goals, marketing focus, or branding interests), please contact our corporate sales department at corpsales@pearsoned.com or (800) 382-3419.

For government sales inquiries, please contact
governmentsales@pearsoned.com.

For questions about sales outside the U.S., please contact
intlcs@pearson.com.

Editor-in-Chief

Brett Bartow

Executive Editor

Loretta Yates

Development Editor

Rick Kughen

Sponsoring Editor

Charvi Arora

Managing Editor

Sandra Schroeder

Senior Project Editor

Tracey Croom

Copy Editor

Rick Kughen

Indexer

James Minken

Proofreader

Scout Festa

Technical Editor

John E. Ray

Editorial Assistant

Cindy Teeters

Cover Designer

Twist Creative, Seattle

Compositor

Danielle Foster

Graphics

Danielle Foster

To Imogen

About the author

Rob Miles spent more than 30 years teaching programming at the University of Hull in the United Kingdom. He now runs a company promoting community uptake of computer technology. He’s a Microsoft MVP with a passion for programming and creating new things. If he had any spare time, he’d spend it writing even more code. He loves building devices and then switching them on to see what they do. He reckons that programming is the most creative thing you can learn how to do. He claims to know a lot of really good jokes, but nobody has ever heard him tell one. If you want an insight into the Wacky World™ of Rob Miles, you can read his blog at www.robmiles.com and follow him on Twitter via @RobMiles.

Contents at a glance

Part 1: The world of JavaScript

Chapter 1   Running JavaScript

Chapter 2   Hypertext Markup Language (HTML)

Chapter 3   Cascading Style Sheets (CSS)

Part 2: Coding with JavaScript

Chapter 4   Working with data

Chapter 5   Making decisions in programs

Chapter 6   Repeating actions in programs

Chapter 7   Creating functions

Chapter 8   Storing data

Chapter 9   Objects

Part 3: Useful JavaScript

Chapter 10 Advanced JavaScript

Chapter 11 Creating applications

Chapter 12 Creating games

Introduction

Programming is the most creative thing you can learn how to do. Why? If you learn to paint, you can create pictures. If you learn to play the violin, you can make music, but if you learn to program, you can create entirely new experiences (and you can make pictures and music, too, if you want). Once you’ve started on the programming path, there’s no limit to where you can go. There are always new devices, technologies, and marketplaces where you can use your programming skills.

Think of this book as your first step on a journey to programming enlightenment. The best journeys are undertaken with a destination in mind, and the destination of this journey is “usefulness.” By the end of this book, you will have the skills and knowledge to write useful programs and make them available to anyone in the world.

But first, a word of warning: I would not say that learning to write programs is easy. This is for two reasons:

If I tell you that it’s easy, and you still can’t do it, you might feel bad about this (and rather cross with me).

If I tell you it’s easy and you manage to do it, you might think that it isn’t worth doing.

Learning to program is not easy. It’s a kind of difficult that you might not have seen before. Programming is all about detail and sequencing. You must learn how the computer does things and how to express what you want it to do.

Imagine that you were lucky enough to be able to afford your own personal chef. At the start, you would have to explain things like, “If it is sunny outside, I like orange juice and a grapefruit for breakfast, but if it is raining, I’d like a bowl of porridge and a big mug of coffee.” Occasionally, your chef would make mistakes. Perhaps you would get a black coffee rather than the latte that you wanted. However, over time, you would add more detail to your instructions until your chef knew exactly what to do.

A computer is like a chef who doesn’t even know how to cook. Rather than saying “make me a coffee,” you would have to say, “Take the brown powder from the coffee bag and add it to hot water.” Then you would have to explain how to make hot water and how you must be careful with the kettle and so on. This is hard work.

It turns out that the key to success as a programmer is much the same as for many other endeavors. To become a world-renowned violin player, you will have to practice a lot. The same is true for programming. You must spend a lot of time working on your programs to acquire code-writing skills. However, the good news is that just as a violin player really enjoys making the instrument sing, making a computer do exactly what you want turns out to be a very rewarding experience. It gets even more enjoyable when you see other people using programs that you’ve written and finding them useful and fun to use.

How this book fits together

I’ve organized this book in three parts. Each part builds on the previous one with the aim of turning you into a successful programmer. We start off discovering the environment in which JavaScript programs run. Then we learn the fundamentals of programming and we finish by making some properly useful (and fun) programs.

Part 1: The world of JavaScript

The first part gets you started. You’ll discover the environment in which JavaScript programs run and learn how to create web pages containing JavaScript programs.

Part 2: Coding with JavaScript

Part 2 describes the features of the JavaScript that you use to create programs that work on data. You will pick up some fundamental programming skills that apply to a wide range of other languages and that get you thinking about what it is that programs actually do. You’ll find out how to break large programs into smaller elements and how you can create custom data types that reflect the specific problem being solved.

Part 3: Useful JavaScript

Now that you can make JavaScript programs, it’s time to have some fun with them. You’ll discover how to create good-looking applications, learn how to make programs that are secure and reliable, and finish off with a bit of game development.

How you will learn

In each chapter, I will tell you a bit more about programming. I’ll show you how to do something, and then I’ll invite you to make something of your own by using what you’ve learned. You’ll never be more than a page or so away from doing something or making something unique and personal. After that, it’s up to you to make something amazing!

You can read the book straight through if you like, but you’ll learn much more if you slow down and work with the practical parts along the way. Like learning to ride a bicycle, you’ll learn by doing. You must put in the time and practice to learn how to do it. But this book will give you the knowledge and confidence to try your hand at programming, and it will also be around to help you if your programming doesn’t turn out as you expected. Here are some elements in the book that will help you learn by doing:

MAKE SOMETHING HAPPEN

Yes, the best way to learn things is by doing, so you’ll find “Make Something Happen” elements throughout the text. These elements offer ways for you to practice your programming skills. Each starts with an example and then introduces some steps you can try on your own. Everything you create will run on Windows, macOS, or Linux.

CODE ANALYSIS

A great way to learn how to program is by looking at code written by others and working out what it does (and sometimes why it doesn’t do what it should). The book contains more than 150 sample programs for you to look at. In this book’s “Code Analysis” challenges, you’ll use your deductive skills to figure out the behavior of a program, fix bugs, and suggest improvements.

WHAT COULD GO WRONG

If you don’t already know that programs can fail, you’ll learn this hard lesson soon after you begin writing your first program. To help you deal with this in advance, I’ve included “What Could Go Wrong” elements, which anticipate problems you might have and provide solutions to those problems. For example, when I introduce something new, I’ll sometimes spend some time considering how it can fail and what you need to worry about when you use the new feature.

PROGRAMMER’S POINTS

I’ve spent a lot of time teaching programming, but I’ve also written many programs and sold a few to paying customers. I’ve learned some things the hard way that I really wish I’d known at the start. The aim of “Programmer’s Points” is to give you this information up front so that you can start taking a professional view of software development as you learn how to do it.

“Programmer’s Points” cover a wide range of issues, from programming, to people, and to philosophy. I strongly advise you to read and absorb these points carefully—they can save you a lot of time in the future!

What you will need

You’ll need a computer and some software to work with the programs in this book. I’m afraid I can’t provide you with a computer, but in the first chapter, you’ll find out how you can get started with nothing more than a computer and a web browser. Later, you’ll discover how to use the Visual Studio Code editor to create JavaScript programs.

Using a PC or laptop

You can use Windows, macOS, or Linux to create and run the programs in the text. Your PC doesn’t have to be particularly powerful, but these are the minimum specifications I’d recommend:

A 1 GHz or faster processor, preferably an Intel i5 or better.

At least 4 gigabytes (GB) of memory (RAM), but preferably 8 GB or more.

256 GB hard drive space. (The JavaScript frameworks and Visual Studio Code installations take about 1 GB of hard drive space.)

There are no specific requirements for the graphics display, although a higher-resolution screen will enable you to see more when writing your programs.

Using a mobile device

You can run JavaScript programs on a mobile phone or tablet by visiting the web pages in which the programs are held. There are also some applications that can be used to create and run JavaScript programs, but my experience has been that a laptop or desktop computer is a better place to work.

Using a Raspberry Pi

If you want to get started in the most inexpensive way possible, you can use a Raspberry Pi running the Raspbian operating system. This has a Chromium-compatible browser and is also capable of running Visual Studio Code.

Downloads

In every chapter in this book, I’ll demonstrate and explain programs that teach you how to begin to program—and you can then use that code to create programs of your own. I’ve made a few video walkthroughs for some crucial tasks. The book text will contain screenshots that you can use, but these can go out of date. Follow the links to the walkthroughs to get the latest steps to follow. You can download the book’s sample code and video walkthroughs from the following page:

MicrosoftPressStore.com/BeginCodeJavaScript/downloads

Follow the instructions you’ll find in Chapter 1 to install the sample programs and code. You’ll discover how to use GitHub to make your own copy of the sample programs. You can then use GitHub to publish JavaScript-enabled web pages for anyone in the world to view. You will need to connect to the Internet and create a free GitHub account to do this. You can browse the GitHub site and all the examples here:

www.begintocodewithjavascript.com

Video walkthroughs

You can also find the walkthroughs here:

https://bit.ly/3wEn6zX

Acknowledgments

Thanks to Mary for the cups of tea and Immy for the distraction.

Errata, updates, and book support

We’ve made every effort to ensure the accuracy of this book and its companion content. You can access updates to this book—in the form of a list of submitted errata and their related corrections—at

MicrosoftPressStore.com/BeginCodeJavaScript/errata

If you discover an error not already listed, please submit it to us at the same page.

For additional book support and information, please visit

http://www.MicrosoftPressStore.com/Support

Please note that product support for Microsoft software and hardware is not offered through the previous addresses. For help with Microsoft software or hardware, go to

http://support.microsoft.com

Stay in touch

Let’s keep the conversation going! We’re on Twitter:

http://twitter.com/MicrosoftPress

Part 1
The world of JavaScript

We are going to start our journey by looking at the world of JavaScript. We’ll begin by considering just what it is that a programming language does. Then we’ll investigate the JavaScript programming language and discover how JavaScript programs get to run on your computer. We’ll learn how web pages provide an environment for JavaScript and how to use Hypertext Markup Language (HTML) and Cascading Style Sheets (CSS) to create containers for our JavaScript programs. We’ll discover just how powerful modern web browsers are as software development tools and how to have a conversation with JavaScript from within a browser. We’ll also learn how to manage our software source code and share it with others.

1
Running JavaScript

What you will learn

Programmers have a set of tools and techniques they use when they create programs. In this chapter, you’re going to discover how JavaScript programs run on a computer. You’ll also have your first of many conversations with the JavaScript command prompt and investigate your first JavaScript program. Finally, you’ll download the Git and Visual Studio Code tools and the example programs for this book and do some simple editing.

What is JavaScript?

Our first brush with JavaScript

A web page with secrets

Tools

Install Git

Install Visual Studio Code

Clone the sample repository

Edit the secret program

What you have learned

What is JavaScript?

Before we go off and look at some JavaScript, it’s worth considering just what we are running. JavaScript is a programming language. In other words, it’s a language that you use to write programs. A program is a set of instructions that tells a computer how to do something. We can’t use a “proper” language like English because “proper English” is just too confusing for a computer to understand. As an example, I give you the doctor’s instructions:

Click here to view code image

"Drink your medicine after a hot bath."

We would probably have a hot bath and then drink our medicine. A computer would probably drink the hot bath and then drink its medicine. You can interpret the above instructions either way because the English language allows you to write ambiguous statements. Programming languages must be designed so that instructions written using them are not open to interpretation; they must tell the computer precisely what to do. This usually means breaking actions down into a sequence of simple steps:

Step1: Take a hot bath
Step2: Drink your medicine

We can get this effect in English (as you can see above), but a programming language forces us to write instructions in this way. JavaScript is one of many programming languages that have been invented to provide humans with a way of telling the computer what to do.

In my programming career, I’ve learned many different languages over the years, and I confidently expect to have to learn even more in the future. None of them are perfect, and I see each of them as a tool that I would use in a particular situation, just like I would choose a different tool depending on whether I was making a hole in a brick wall, a pane of glass, or a piece of wood.

Some people get very excited when talking about the “best” programming language. I’m quite happy to discuss what makes the best programming languages, just like I’m happy to tell you all about my favorite type of car, but I don’t see this as something to get worked up about. I love JavaScript for its power and the ease with which I can distribute my code. I love Python for its expressiveness and how I can create complex solutions with tiny bits of code. I love the C# programming language for the way it pushes me to produce well-structured solutions. I love the C++ programming language for the way that it gives me absolute control of hardware underneath my program. And so on. JavaScript does have things about it that make me want to tear my hair out in frustration. But that’s true of the other languages, too. And all programming languages have things about them I love. But most of all, I love JavaScript for the way that I can use it to pay my bills.

PROGRAMMER’S POINT

The best programming language for you is the one that pays you the most

I think it is very fitting that the first programmer’s point is one that has a strong commercial focus. Whenever I get asked which is the “best” programming language, I always say that my favorite language is the one that I get paid the most to use. It turns out that I’ll write in any programming language if the price is right.

I strongly believe that you can enjoy programming in any language, and that includes JavaScript. Conversely, you can have a horrible time writing bad programs in any language. The language is just the medium which you use to express your ideas.

So, if you tell someone that you’re writing JavaScript programs and they tell you that it’s not a very good programming language for reasons that you don’t understand, just show them how many jobs there are out there for people who can write JavaScript code.

JavaScript origins

You might think that programming languages are a bit like space rockets in that they are designed by white-coated scientists with mega-brains who get everything right the first time and always produce perfect solutions. However, this is not the case. Programming languages have been developed over the years for all kinds of reasons, including ones like, “It seemed a good idea at the time.”

JavaScript was invented by Brendan Eich of Netscape Communications Corporation and first appeared in a Netscape web browser that was released at the end of 1995. The language had a variety of names before the company decided on JavaScript. It turned out to be a poor choice of name because it makes it easy to confuse JavaScript with the Java programming language, which is actually quite different from JavaScript.

JavaScript was intended as a simple way of making web pages interactive. Its name reflects the way that it was supposed to be used alongside Java applications (called applets) running in a web browser. However, JavaScript was extended beyond all the expectations of its creator and is now one of the most popular programming languages in the world. Whenever you visit a website, it is almost certain that you will be talking to a JavaScript program.

This book will teach you JavaScript, but actually I’m trying to turn you into a programmer. The fundamentals of program creation are the same for JavaScript and pretty much all programming languages. Once you’ve learned how to write JavaScript, you’ll be able to transfer this skill into many other languages, including C++, C#, Visual Basic, and Python. It’s a bit like the way that once you have learned to drive, you can drive any vehicle. When you are using a strange car, you just need to find out where the various switches and controls are, and then you can set off on your journey.

JavaScript and the web browser

The inventor of JavaScript intended for it to be used in a web browser, and that is where we are going to start using it. It is possible to create JavaScript programs that run outside the browser, we will consider how to do this in the third part of this text. You can use any modern browser, but the exercises in this text use a browser based on the Chromium framework. I’m using Microsoft Edge, which is available for Windows or macOS. You can use Google Chrome or the Chromium browser for Linux if you prefer.

Our first brush with JavaScript

You’ve reached a significant point in the process of learning how to program. You’re about to begin exploring how programs work. This is a bit like opening the front door of a new apartment or house or getting into a shiny new car you’ve bought. It’s an exciting time, so take a deep breath, find a nice cup (or glass) of something you like to drink, and settle down comfortably.

You are going to start by doing something that you’ve done thousands of times in the past. You are going to visit a site on the World Wide Web. But then, with a single press of a key, you’re going to explore a world behind the web page and get a glimpse of the role that JavaScript plays in making it work.

MAKE SOMETHING HAPPEN

A web page with secrets

First, you need to open your browser, and then visit the following web page, which is shown in Figure 1-1:

http://www.begintocodewithjavascript.com/hello

Figure 1-1 A web page with secrets

This looks like a very ordinary web page, but it holds a secret behavior that you can find by pressing the F12 key on your keyboard. Figure 1-2 shows the Developer View.

Figure 1-2 The Developer View

This is called Developer View. It shows all the elements that make up the web page. A complete description of everything you can do in this view would not fit in this book. Don’t be worried about how complicated it all looks, we are only going to use a couple of the features. We are going to start by looking at the elements that make up the text on the page. Make sure that the Elements tab is selected as you can see in Figure 1-2. Then look at the text underneath, which is shown in Figure 1-3.

Figure 1-3 Page elements

Figure 1-3 shows the elements on this page. You can see that the text that appears on the page is here. Parts of the text are enclosed in what look like formatting instructions, for example some is marked as <h1> and some as <p>. If you look back at the web page as displayed you will notice that the <h1> text is in a large heading font, whereas the <p> text is in smaller text. This is how pages are formatted. You can see how the page works, but where is the secret? To answer this, click the right-pointing arrowhead at the left of the word script to open this part of the view (see Figure 1-4).

Figure 1-4 doAddition function

Clicking the arrow opens that part of the listing. The hidden feature is a function called doAddition. This takes two numbers, adds them together, and displays the result using an alert. Later in the text, we will go into detail of how this JavaScript works, but even at this stage, it is quite clear what is going on.

However, this function is never actually used in the web page. We can use it ourselves by entering it into the JavaScript console, which is built into the browser. This performs JavaScript statements that you type in. You can open the console by selecting the Console tab at the top of the window (see Figure 1-5).

Figure 1-5 JavaScript console

This is the Console window. I’ve typed in the name of the function and given it two numbers to work on. When the function runs it display an alert with the result it has calculated, as shown in Figure 1-6.

Figure 1-6 Result alert

We can use the JavaScript console to type in other JavaScript commands. You can use JavaScript to perform calculations by just entering them. When you press the Enter key, the answer will be displayed. In fact, the console is often keen to give you an answer even before you press Enter. The console will also try to help as you type in by suggesting what you might be typing. You can accept any suggestion by using the cursor key to select the suggestion and then pressing the Tab key.

CODE ANALYSIS

Talking to JavaScript

We can learn a little about the way JavaScript works by giving the JavaScript console some commands and considering the responses.

> 2+3

This looks like a sum, and as you might expect, you get a number for an answer

<-5

We can repeat this with something other than a number:

> "Rob"+" Miles"

Some text enclosed in double quotes is interpreted by JavaScript as a string of text, and it is perfectly happy to use + to add two strings together. Note that if you want to have a space between the two words in the sum, you have to actually put it into the strings that you add together. (In my example above, there is a space in front of the ‘M’ in the second word.)

<- "Rob Miles"

We can do other kinds of sums. For example, we can subtract using minus (-).

>  6-5

This produces the result that you would expect.

<-  1

JavaScript seems quite happy when we ask it to do sensible things. Now, let’s try asking it to do something stupid. What do you think would happen if we tried to subtract one string from another using the following statement?

> "Rob"-" Miles"

While it seems sensible to regard + as meaning “add these strings together,” there doesn’t seem to be a sensible interpretation of minus (-) when you are working with strings. In other words, it is meaningless to try and subtract one string from another. If you enter this into the console, you get a strange response from JavaScript:

<-  NaN

The JavaScript console is not calling for grandma to come and sort the problem out. The value NaN means “not a number”. It is a way that JavaScript indicates that the result of a calculation has no meaning. Some programming languages would display an error message and stop a program if you tried to use them to subtract one string from another. JavaScript does not work like this. It just generates a result value that means “this result is not a number” and keeps going. We will consider how to a program can manage errors like this later in the text.

And because we are talking about errors, how about asking JavaScript to do some silly math:

>  1/0

When I got my first pocket calculator, the first thing I tried to do with it was calculate one divided by zero. I was richly rewarded by a result that just kept counting upward. What do you think JavaScript will do?

<-  Infinity

JavaScript says that the result of the calculation is the value Infinity. This is another special value that is generated by JavaScript when it does calculations. Talking of calculations, how about asking JavaScript to do another one for us?

>  2/10+1/10

This calculation involves real numbers (meaning ones with a fractional part). The calculation is adding 0.2 to 0.1 (a fifth to a tenth). This should produce the result 0.3, but what we get is interesting:

<-  0.30000000000000004

This number is very, very close to 0.3 (the correct answer), but it is ever-so-slightly larger than it should be. This illustrates an important aspect of the way that computers work. Some values that we can express very easily on paper are not held exactly by the machine. This is only usually a problem if we start performing tests with the values that we calculate, such as a check to see if the calculated result above was equal to the value 0.3 might fail because of the tiny difference. Let’s see if we can use JavaScript to do some things for us. How about this?

>  alert("Danger: Will Robinson")

This statement doesn’t calculate a result. Instead, it calls a function called alert. The function is provided with a string of text. It asks the browser to display the string as a message in an alert box, as shown in Figure 1-7.

Figure 1-7 Danger: Will Robinson

This is how the doAddtion function displays the result it has calculated. Finally, let’s try another function called print:

>  print()

What you will see next depends on the computer and the browser that you are using, but you should see a print window appear, which offers you the chance to print the web page. If you’ve ever wondered what happens when you press the Print button on a web page, you know now.

Congratulations. You now know how web pages work. Your browser fetches a file from the server and then follows the instructions in that file to build a page for you to look at. The file contains text that is to be displayed on the page, along with formatting instructions. A page file can also contain JavaScript program code.

The instructions that the browser follows are expressed in a language called Hypertext Markup Language (HTML). In the next chapter, we’ll take a detailed look at HTML, but before we do that, we need to get some tools that will let us fetch the sample code for this book onto our computer and work with HTML and JavaScript.

Tools

You will need some software tools to get the best out of the exercises in this book. We are going to start with two, a program called Git that will manage the program files that we work on and a program called Visual Studio Code, which we will use to work on the files. Neither of these will cost you any money, and they are available for Windows, macOS, and Linux. You can follow through the printed instructions below, or you can use one of my video walkthroughs that you can find here:

https://www.begintocodewithjavascript.com/media

PROGRAMMER’S POINTS

Git and Visual Studio Code are professional tools

When you learned to ride a bike, you probably had one with training wheels. And people learning to drive a car usually start in something small and easy to handle. You are learning programming with the tools that professionals work with. This is a bit like learning to drive using a Formula 1 racing car. However, there is nothing to worry about here. A Formula 1 car might look a bit scary, but it still has a steering wheel and the usual set of pedals. And you don’t have to drive it fast if you don’t want to.

GitHub and Visual Studio code have a huge range of features, but you don’t have to use them. Just like there are buttons on my car dashboard that I don’t press because I’m not sure what they do, you don’t have to know about every feature of these tools to make good use of them.

It is very sensible to start developing with “proper” tools because job recruiters are often as interested in the tools that you are familiar with as they are with the programming languages that you can work with.

Getting Git

The source code of programs that you write is stored on your computer as files of text. These files are called “source code”. You work on your programs by changing the contents of these files. When I was starting out programming, I learned very quickly that you can go backward as well as forward when writing software. Sometimes, I would spend a lot of time making changes to my programs that would turn out to be a bad idea, and I would have to go back and undo them all. I solved this problem by making copies of my program code before I did any major edits. That way, if anything went bad, I could go back to my original files.

Lots of other programmers noticed this problem, too. They also noticed that if you release a program to users, it is very useful to have a “snapshot” of that code so that you can keep track of any changes that you make. The best programmers are great at being “intelligently lazy,” so they created source code management (SCM) software to manage this. One of the most popular programs is called Git.

Git was created in 2005 by Linus Torvalds who was writing the Linux operating system at the time. He needed at tool that could track what he was doing and make it easy for him to work with other people. So, he created his own. Git is a professional tool and very powerful. It lets large numbers of developers work together on a single project. Different teams can work on their own versions of the code, which can them be merged. There is no need for you to use all of these powerful features, though. You’re just going to use Git to keep track of our work and as a way of obtaining the example programs.

MAKE SOMETHING HAPPEN

Install Git

I’m going to give you instructions for Windows 10. The instructions for macOS are very similar. First, you need to open your browser and visit this web page, which is also shown in Figure 1-8:

https://git-scm.com

Figure 1-8 Git installation page

Follow the installation process, selecting all the defaults.

Getting Visual Studio Code

If you want to write a letter, you would use a word processor. To perform calculations, you might use a spreadsheet. Visual Studio Code is a tool that you can use to edit your program files. It can do a lot more than this, as we shall see later. But for now, we are going to use it as a super-powerful program editor. Visual Studio Code is free.

MAKE SOMETHING HAPPEN

Install Visual Studio Code

I’m going to give you instructions for Windows 10. The instructions for macOS are very similar. First, you need to open your browser and visit this web page, which is shown in Figure 1-9:

https://code.visualstudio.com/Download

Figure 1-9 Visual Studio Code download page

Click the version of Visual Studio Code that you want and follow the instructions to install it. Once it is installed, you will see the start page shown in Figure 1-10.

Figure 1-10 Visual Studio Start page

Now that you have Visual Studio installed, the next thing you need to do is fetch the sample files to work on.

Getting the sample files

The sample programs, along with a lot of other stuff, are stored on GitHub. GitHub is a service that is underpinned by the Git system. You can store your own files on GitHub (and not just programs). You can also use GitHub to host web pages containing JavaScript programs that you create. For now, we are going to just download the sample repository and edit the hello.html file that we worked with at the start of this chapter.

MAKE SOMETHING HAPPEN

Clone the sample repository

A repository in Git is a collection of files. Whenever I start working on something new, I create a repository to hold all the files I’m going to create. I’ve got a private repository that contains all the text of this book. And I’ve made a public repository to hold the sample files. Repositories on GitHub can be accessed directly from the browser. The sample files for this book are at the repository with this URL (uniform resource locator):

https://github.com/begintocodewithjavascript/begintocodewithjavascript.github.io

If you visit this URL with your browser, you will find that you can navigate all the files, including the file hello.html, which we investigated earlier, and take a look at what is inside them. See Figure 1-11.

Figure 1-11 Repository home page

You can see that GitHub is keeping track of the changes that I have made to the example programs. We are going to use Visual Studio Code to clone this repository. Start Visual Studio Code and click the Source Control button, as shown in Figure 1-12.

Figure 1-12 Visual Studio Source Control button

This opens the Source Control dialog, as shown in Figure 1-13. Next, click the Clone Repository button to begin the process of fetching a repository from GitHub.

Figure 1-13 Visual Studio Code source clone repository

Visual Studio code will download the contents of the repository and store them on your machine. Enter the URL of the repository in the dialog that appears:

https://github.com/begintocodewithjavascript/begintocodewithjavascript.github.io

When you press Enter at the end of the URL, as shown in Figure 1-14, you will be asked where on your computer you want to put the files that are about to be copied. I suggest that you create a folder named GitHub in your Documents folder and use that, but you can put the repository anywhere you like. Once you’ve selected the folder, Visual Studio will copy all the files in the repository from the GitHub site to your computer.

Figure 1-14 Visual Studio Code repository clone complete

When all the files have been copied, Visual Studio Code will ask if you want to open the repository. Click Open to open it.

Congratulations, you have cloned you’re first repository! Remember that you can use GitHub to store anything that you might want to work on, not just program files. If you have an assignment to write, you could create a repository to hold the documents and images. This would be an even better idea if you were working on the assignment with other people because GitHub is a great collaboration tool.

Working on files with Visual Studio Code

We can round off this chapter by working the JavaScript program that we saw at the very start. The process we are going to follow will look like this:

Edit the program in the HTML file.

Save the file back to disk.

Use a web browser to view the HTML file and see what it does.

This is the process you will be using for a lot of the material covered in the rest of the book.

MAKE SOMETHING HAPPEN

Edit the secret program

At the end of the last session, you opened the example repository that you’d downloaded from GitHub. Now you get to edit the hello.html file that we saw contains the secret program. The Explorer window at the left-hand side of the Visual Studio Code window provides a view of all the files and folders in the repository. There are lots of files here, including ones that contain the source code website at begintocodewithjavascript.com. You can click the > in front of folders in the Explorer view to open them and view their contents. See Figure 1-15.

Figure 1-15 Visual Studio Code example repository

For now, you are just going to look in the hello.html file, so click the hello.html file name in the Explorer to open it (see Figure 1-16).

Once the page has opened, you can make some changes to the text in the file. I’ve changed one heading so that it reads “Hello from Rob.” You can save the file by holding down the Control key (Command key on macOS) and pressing S (CTRL+S). Or you could use the Save command in the File menu. Either way, you now want to view the changed file in a browser to see if the changes have worked.

Figure 1-16 Editing the hello.html file

When you cloned the repository, you told Visual Studio Code where to put the files, so now is the time to open File Explorer and navigate to that folder. If you’ve forgotten where you put the files, you can find out just by hovering your mouse pointer over the file name in Explorer. Visual Studio Code will then show you the path to that file (see Figure 1-17).

Figure 1-17 Finding the hello.html file

If we double-click this file, it will be opened by the browser, as shown in Figure 1-18.

Figure 1-18 The hello.html file open in a browser

Now you will see the file in all its edited glory. Note that the address being browsed is now a file on your local storage, rather than on the web. Note also that you can press F12 if you like and view the contents of the file, just like we did at the start of this chapter.

What you have learned

You might feel that you’ve spent a lot of this chapter just following instructions, but actually you’ve learned rather a lot. You’ve discovered that JavaScript is a programming language that provides a means by which you can tell a computer how to do something. You’ve had a conversation with JavaScript itself. You’ve learned that looking after the source files of your programs is important, although great programmers sometimes think of very silly names (for example, Git) for their programs. You’ve installed the Git system and your program editor, Visual Studio Code. Finally, you’ve copied all the example code onto your machine by “cloning” the repository held on GitHub and even managed to edit one file and view the effects in your browser.

To reinforce your understanding of this chapter, you might want to consider the following “profound questions” about JavaScript, computers, programs, and programming.

What does the word “script” mean in the name JavaScript?

The word “script” in the JavaScript name refers to the way that JavaScript programs were intended to run. The browser would read each JavaScript statement and then perform it, just like an actor would act out the script of a play. This is not how all programming languages work. Some programming languages are designed to be compiled. This means that the source code of the program is converted into the low-level instructions that are run by the computer hardware. These low-level instructions are then directly obeyed by the hardware to make the program run.

Compiled languages run faster than scripts because when the compiled program runs, the computer doesn’t have to put any effort into working out what the program source is doing; it can just obey the low-level instructions. However, you need to make a different version of the compiled code for each type of computer. For example, a compiled file for a Windows PC would not run on a Raspberry Pi.

JavaScript was intended to perform simple tasks inside a browser, so it was created as a scripting language. However, it has now become so popular that modern browsers compile JavaScript before running it so that it runs as quickly as possible.

Does my JavaScript program run on the web server?

No. The job of a web server is just to serve up files. The browser (the program running on the user’s computer) is responsible for actually creating the display of a web page and running any JavaScript programs in that page.

Do JavaScript programs run at the same speed on all computers?

No. The faster the host computer, the faster the browser (and the JavaScript programs it is hosting) will run.

Do JavaScript programs run faster if I have a faster network connection?

No. A faster network connection will improve the speed at which the JavaScript programs will be loaded into the browser, but the actual speed the JavaScript program runs is determined by the speed of the host computer. Having said that, if the JavaScript program uses the host computer network connection, these actions will, of course, happen more quickly.

Can we view the JavaScript programs in every page we visit?

Yes, you can. The F12 trick (pressing F12 when viewing a web page in a browser) will open the development view of the page. You can use this to view the JavaScript source code in the page. If you are concerned about someone copying the JavaScript code, you can use a tool called an obfuscator, which is a piece of software that changes the appearance (but not the behavior) of a program so that it is very hard to understand. Take a look at https://www.javascriptobfuscator.com/ for more details.

How big can a JavaScript program be?

A JavaScript program can be very large indeed. Modern web browsers are very good at handling large programs, and the speed of modern networks means that the code can be downloaded very quickly. Some people have even created complete computer emulations in JavaScript that you can run in a browser.

Can you run JavaScript outside a web browser?

Yes, you can. Some web pages can be converted into applications, which then run on the local computer. There are also ways in which a computer can be made to host JavaScript applications in the same way that a browser does. We will look at these later in the text when we consider the node.js environment in Chapter 11.

Why is Git called “Git”?

This is probably the hardest question in this book. In the UK, the word “git” is a form of mild abuse. You would call someone a “git” if he or she spilled your drink on purpose. It seems that Linus Torvalds called his first version of the program “His stupid content tracker,” and then hit upon the word “git” as a shorter version of this.

Can I do private work on GitHub?

Yes. GitHub is very popular with programmers who are working on open-source projects, but you can also make a GitHub repository private so that only you can see it.

What do I do if I “break” my program?

Some people worry that things they do with a program on the computer might “break” it in some way. I used to worry about this, too, but I’ve conquered this fear by making sure that whenever I do something, I always have a way back. Git and GitHub are very useful in this respect.

Why does the Visual Studio Code display of the hello.html file appear in different colors?

This is called source code highlighting. Visual Studio Code has a list of words that are “special” as far as JavaScript and HTML are concerned. These special words are called keywords. For each keyword, Visual Studio Code has a characteristic color. In the case of Visual Studio Code, keywords are displayed in blue, functions are displayed in yellow, strings of text are orange, and everything else is white. The intention is to make it easier for programmers to understand the structure of the program. Note that there is nothing in the program file that specifies the color of each element; this is something that Visual Studio Code does.

What is the difference between Visual Studio Code and Visual Studio?

Microsoft produces two tools, one called Visual Studio and the other called Visual Studio Code. They can both be used to create programs. We are using Visual Studio Code which, as its name implies, is designed for working with source code. Visual Studio is a much more comprehensive suite of tools that can be used to manage large teams of developers working on huge projects. There is a free version of Visual Studio available that you can download and install if you wish, but how to use it is a bit beyond the scope of this text.

2
Hypertext Markup Language (HTML)

What you will learn

In the previous chapter, you learned that a JavaScript program can live inside a web page. You saw that the file hello.html had a secret script inside it. In this chapter, we will find out more about the HTML standard that tells the browser program what a web page should look like. Then we’ll discover how to link JavaScript to elements on a web page to allow our programs to interact with the user.

HTML and the World Wide Web

What is HTML?

Making active web pages

Work with object properties

Egg timer

Investigate the egg timer

An image display program

Create your own pages

What you have learned

HTML and the World Wide Web

The first version of a Hypertext Markup Language (HTML) was created in 1989 by Tim Berners-Lee. He wanted to make it easier for researchers to share information. At the time, research reports were written as individual documents. If a document you were reading contained a reference to another document, you would have to go and find the other one. Tim Berners-Lee designed a system of computer servers to share electronic copies of documents. A document could contain hyperlinks to other documents. Readers used a browser program to read the document from the servers and follow the links from one document to another. These documents are called hypertext documents, and the language that described their contents is called the Hypertext Markup Language, or HTML.

Tim Berners-Lee also designed a protocol to manage the transfer of HTML-formatted documents from the server into the browser. This standard is called the Hypertext Transfer Protocol, or HTTP. Also, now there is a secure version of this protocol called HTTPS, which adds security to the web. HTTPS allows a browser to confirm the identity of a server, and it also protects messages sent between the server and the browser to prevent eavesdropping. The HTTPS protocol is what makes it possible for us to use the World Wide Web for banking and e-commerce.

In 1990, the first system was released as the “World Wide Web.” The documents that you could download were called “web pages.” The server hosting the web pages was called a “website.” In 1993, Marc Andreessen added the ability to display images in web pages, and the web became extremely popular.

The World Wide Web was designed to be extensible, and for many years, different browser manufacturers added their own enhancements to the standards, leading to problems with compatibility where websites would only work with specific browser programs. Recently, the situation has stabilized. The World Wide Web Consortium (W3C) now sets out standards that are implemented by all browser manufacturers. The latest standard, HTML5, is now very stable and is the version used in this book.

Fetching web pages

The location of the page on a server is given using a uniform resource locator, or URL. This has three elements:

The protocol The protocol is used to talk to the site. This sets out how a browser asks for a web page, and how the server replies. Web pages use HTTP and HTTPS. HTTP stands for “Hypertext Transport Protocol” and HTTPS is the secure version of this protocol.

The host This gives the address of the server on the network. The World Wide Web sits on top of a networking protocol called TCP/IP (Transport Control Protocol/Internet Protocol), and this is the address on that network of the system that holds the website you want to connect to.

The path This is the host’s path to the item that the browser wants to read.

You can see all these elements in the URL that we used to access the hello.html page in Chapter 1 (see Figure 2-1).

Figure 2-1 URL structure

This URL specifies that the site uses the secure version of the hypertext transfer protocol, that the address of the host server is begintocodewithjavascript.com, and that the path to the file containing the web page is hello.html. If you leave off the path, the server will deliver the contents of a default file which might be called index.html or Default.htm or some other name, depending on how the server has been set up.

When the user requests a website, the browser sends a message to the server to request the page. This message is formatted according to the Hypertext Transport Protocol (HTTP) and is often called a “get” request (because it starts with the word GET). The server then sends a response that includes a status code and then, if it is available, the text of the web page itself is sent. If the page cannot be found on the server (perhaps because the URL was not given correctly), the HTTP status code results in the familiar “404 page not found” message. We will learn more about this process later in the book when we write some JavaScript code that gets web pages.

What is HTML?

This is not a guide to HTML. You can buy whole books that do a very thorough job of describing the language and how it is used. But you should finish this section with a good understanding of the fundamentals. HTML is a markup language. Markup is what the “M” in HTML stands for. The word “markup” comes from the printing profession. Printers would be given text that had been “marked up” with instructions such as “print this part in large font” and “print this part in italic.”

Figure 2-2 shows what happens if you don’t use a markup language properly. In this case, the customer wanted a cake with no writing on it. The customer said, “Please Leave Blank” when asked what she wanted written on the cake. Unfortunately, the baker took this instruction literally.

Figure 2-2 Markup taken literally

This kind of misunderstanding is impossible with HTML. The language has a rigid separation between the text that is to be displayed and the formatting instructions. In HTML, if I want something to be emphasized, I will use an HTML markup command to request this:

Click here to view code image

<em>This text is emphasized.</em> This text is not.

The sequence <em> is recognized by the browser as meaning “make the text that follows this instruction look slightly different from the other text” and is called a tag. The browser will display emphasized text until it sees the sequence </em>, which marks the end of the emphasized text. Most browsers emphasize text by displaying it as italic. If we viewed the above HTML in a Microsoft Edge, we would see something that looks like this:

Click here to view code image

This text is emphasized. This text is not.

Once you understand the fundamentals of HTML, you can use it to format text. The HTML below shows a few more tags.

Click here to view code image

This is <em>emphasized</em><br>
This is <i>italic</i><br>
This is <strong>strong</strong><br>
This is <b>bold</b><br>
This is <small>small</small><br>
This is <del>deleted</del><br>
This is <ins>inserted</ins><br>
This is <u>underlined</u><br>
This is <mark>marked</mark><br>

The example HTML above uses a tag, <br>, that means “start on a new line.” The <br> tag does not need to be matched by a </br> element to “close it off.” This is because it has an immediate effect on the layout; it is not “applied” to any specific items on the page. When I pass this text into a browser, I get the output shown in Figure 2-3.

Figure 2-3 The <br> tag creates a new line of text.

If you look closely at the text in Figure 2-3, you will notice that some of the requests have similar results. For example, the emphasized (<em>) and italic (<i>) formats both produced italic output. The bold (<b>), italic (<i>), and underline (<u>) tags are regarded as slightly less useful than the more general ones, such as emphasized (<em>) or strong (<strong>). The reasoning behind this is that if a display has no way of producing italic characters a request to display something in italic is not going to work.

However, if the display is asked to “emphasize” something, it might be able to do this in a different way, perhaps by changing the color of the text. Output produced by HTML is intended to be displayed in a useful way on a huge range of output devices. When you use a markup language, you should be thinking about the effect you want to add to a piece of text. You should think “I need to make this stand out, so I’ll use the <strong> format,” rather than just making the text bold.

You can write the commands using uppercase or lowercase or any combination of the two. In other words, the tags <em>, <EM>, and <Em> are all regarded as the same thing by the browser.

Display symbols

By now, you should have a good idea how HTML works. A tag <blah> marks the start of something. The sequence </blah> marks the end. The tags can be nested (placed inside each other).

Click here to view code image

<em>This is emphasized <strong>This is strong and emphasized</strong></em>

This HTML would generate:

Click here to view code image

This is emphsized This is strong and emphasized

For every start tag (<blah>) that marks a formatted area of text, there should be a matching end tag (</blah>). Most browsers are quite tolerant if you get this wrong, but the display that you get might not be what you want.

The question you are probably asking now is, “How I can ever get to display the < (less than) and > (greater than) symbols in my web pages?” The answer is that HTML uses another character to mark the start of a symbol entity. The & character marks the start of a symbol. Symbols can be identified by their names:

Click here to view code image

This is a less than: &lt; symbol and this is a greater than &gt; symbol

The name of the less than character (<) is lt, and the name of the greater than (>) symbol is gt. Note that the end of a symbol name is marked by a semicolon (;). If you are now wondering how we display an ampersand (&), the answer is that it has the symbol name amp.

Click here to view code image

This is an ampersand: &amp;

You can find a handy list of symbols and their names here: https://dev.w3.org/html5/html-author/charref. Note that when you give a symbol a name, the case of the names is significant.

&Eacute;<br>
&eacute;<br>

The HTML above would display the uppercase (É) and lowercase (é) versions of eacute. If you like emojis (and who doesn’t?), you can add these to your web pages by using a symbol that includes the number of the emoji that you want to use.

Happy face: &#128540;<br>

This will display a happy face, as shown in Figure 2-4.

Figure 2-4 Happy face emoji

If you want to discover all the numbers that you can use to put emojis in your web pages, take a look here: https://emojiguide.org/.

WHAT COULD GO WRONG

Make sure your emojis mean the right thing

Emojis are a great way to liven up a user interface, but you need to make sure that you know what you are saying with them. Some emoji designs have particular meanings to specific groups of people that are not immediately obvious. Before you send out your emoji-powered pages, you should check a website such as https://emojipedia.org/ to make sure your page means what you think it does.

Lay out text in paragraphs

We now know how to format text. Next, we must consider how we can lay this text out on the page. When HTML text is displayed, the original layout of the text input is ignored. In other words, consider this text:

Hello
 world

    from   Rob

The layout of this text is a bit of a mess. However, when this text is displayed by a browser, you see the following:

Hello world from Rob

The browser takes in the original text, splits it into words, and then displays the words with single spaces between them. Any layout information in the source text is discarded. This is a good idea because the designer of a web page can’t make any assumptions about the display that will be used. The same page needs to work on large and small displays—from smartphones to large LCD panels.

We’ve seen that the <br> sequence asks the browser to create a new line during the display of text. Now we are going to consider some more commands that control how text is laid out when it is displayed. The <p> and </p> commands enclose text that should appear in a paragraph:

Click here to view code image

<p>This is the first paragraph</p>
<p>This is the second paragraph</p>

This HTML will display two paragraphs:

Click here to view code image

This is the first paragraph
This is the second paragraph

The <br> command is not the same as the <p> command; it does not space the lines out like a paragraph would.

Create headings

We can use other tags to markup text as headings at different levels:

Click here to view code image

<h1>Heading 1</h1>
<h2>Heading 2</h2>
<h3>Heading 3</h3>
<h4>Heading 4</h4>
<p>A normal paragraph</p>

We can use these in documents to create headings, as shown in Figure 2-5.

Figure 2-5 Headings

You can use headings to create structure in a document.

Use preformatted text

But sometimes, you might have something that you have already formatted. In this case, you can use the <pre> tag to tell the browser not to perform any layout:

Click here to view code image

<pre>
This text
  is rendered
    exactly how I wrote it.
</pre>

The text enclosed by the <pre> tags is displayed by the browser without any changes to the formatting.

This text
  is rendered
    exactly how I wrote it.

The browser uses a monospaced font when displaying preformatted text. In a monospaced font all the characters have the same width. Many fonts, including the one used to print this paragraph, are proportional. This means that each character has a particular width; for example, the “I” character is much smaller than the “m” character. However, for text such as ASCII art, it is important that all the characters line up. The code for the logo shown in Figure 2-6 would not look correct if it were not displayed with a monospaced font.

Figure 2-6 A preformatted logo

Note that the ASCII art above contains a < character, which I had to convert to a symbol (&lt;) so that it is displayed correctly. This is important. Remember that the browser will not format preformatted text, but it still observes the character conventions that you must use to display characters and symbols. You can add tags to the preformatted text to make parts of it emphasized; <p> tags inside preformatted blocks of text might work, but this is not advised because it makes your html badly formed. The logo appears as shown in Figure 2-7.

Figure 2-7 My logo

PROGRAMMER’S POINT

Don’t abuse the browser

Browsers are generally very tolerant of badly formatted HTML. The browser will try to display something even if the HTML it receives is badly formatted. This means you can get away with HTML like this:

Click here to view code image

<em>Emphasized <strong>strongly emphazised</em> just strong </strong>

The browser will display what you would expect:

However, it is malformed HTML. You might be wondering why. Let’s take a look at the sequence of tags in the text.

This is an example of what is called bad nesting. This is because the <em> tag “ends” inside the <strong> tag. In properly formed HTML, a tag that is created inside another tag will end before the enclosing tag ends. The complete sequence of a start tag, text, and end tag is called an element. While one element can completely contain another, it is not correct for elements to overlap like the ones in the above figure. The correct version of this HTML is shown below. Note that each element is complete.

The above figure shows what correct nesting looks like. Each element ends before its enclosing one. The reason why I’m stressing this is that most browsers can work out the meaning of the badly nested HTML and display it correctly, but some might not. This could lead to your web pages looking wrong to some people. I’m sure you’ve had the experience of having to switch browsers because a particular website doesn’t look right. Now you know how this can happen.

You can identify incorrectly nested HTML when you see an end tag that doesn’t match the most recent start tag. If you want to use a program to make sure that your HTML is correct, you can use the official validator site at https://validator.w3.org/. You can point the validator at a site you have created or paste HTML text into it for checking.

Add comments to documents

You can add comments to an HTML document by enclosing the comment text in the sequences <!-- and --> as follows:

Click here to view code image

<!-- Document Version 1.0 created by Rob Miles -->

The author credit would not be displayed by the browser, but you could view it in the source code by pressing the F12 key to open the developer view. As we go through this text, I’ll be telling you regularly how useful it is to add comments to your work, so I think it is a good idea to start doing this now.

Add images to web pages

For the first few years of its life, the World Wide Web didn’t have any pictures at all. The image tag was added by Marc Andreessen, one of the authors of Mosaic, the most popular browser in the early days of the web. The image tag contains the name of a file that contains an image:

<img src="seaside.JPG">

The image tag uses an attribute to specify the file that contains the image to be displayed. An attribute is given inside the tag as a name and value pair, separated by the equals character. When the browser finds an img tag, it looks for the src attribute and then looks for an image file with that name. In the case of the above HTML, the browser would look for an image called seaside.JPG. It would look in the same place on the server from which it loaded the web page. We must make sure that file exists on the server; otherwise, the image will not be displayed.

WHAT COULD GO WRONG

Beware of faulty file names

The src attribute in an img tag is followed by the name of the file that is to be fetched from the server. While HTML doesn’t care about the capitalization of tags (you can write IMG, img, or Img for the tag name), the computer fetching the image file might. Some computers will deliver a file stored as seaside.jpg if you ask for one called seaside.JPG. Others will complain that the file is not available.

I normally encounter this problem when I take a website off my PC (where it has been working perfectly) and place it on the server (when all the image files suddenly vanish).

You can add another attribute to an img tag that provides alternative text that is displayed if the image cannot be found.

Click here to view code image

<img src="seaside1.JPG" alt="Waves crashing on an empty beach">

Now the browser will display the text “Waves crashing on an empty beach” if the image can’t be located. The alternative text (ALT) is also very useful for visually impaired web users who can’t see the image but who would appreciate a text description of what is in it.

The image will be displayed in line with the text on the page. We can use the HTML layout tags to lay an image out sensibly with the surrounding text:

Click here to view code image

<h1>Seaside Picture</h1>
<p><img src="seaside.JPG" alt="Waves crashing on an empty beach"></p>
<p>This picture was taken at Hornsea in the UK.</p>

The image shown in Figure 2-8 is 600 pixels wide. A pixel (short for picture cell) is one of the dots that make up the picture. The more pixels that you have, the better looking the picture is.

Figure 2-8 An image that is 600 pixels wide

However, this can cause problems if the picture is too large to fit on the device being used to display the image. The img tag supports width and height attributes that can be used to set the displayed size of an image. So, if I want to display the image as 400 pixels wide I can do this:

Click here to view code image

<p><img src="seaside.JPG" alt="Waves crashing on an empty beach" width="400">

Note that I didn’t specify the height, which means the browser will automatically calculate the height that matches a width of 400 pixels. You can specify both height and width if you like, but you need to be careful not to make the pictures distorted. Setting the absolute width of an image using height and width attributes looks like a good idea at first, but it can be restricting. Remember that an underlying principle of the World Wide Web is that a page should display in a useful way on any device. An image size of 400 pixels might be fine for a small device, but it will appear very small if viewed on a large TV display. In the next chapter, we will discover how we can use style sheets to allow items on a web page to be automatically scaled for the target device.

The HTML document

We now know that we can use tags to mark regions of text as needing to be formatted in a particular way, such as using <em> for emphasized text. We can also mark regions of text as being in paragraphs or levels of headings. We can apply several tags to a given piece of text to allow formatting instructions to be layered on top of each other, but we need to make sure that these instructions are properly “nested” inside each other. Now we can consider how to create a properly formatted HTML document. This comprises several sections:

The browser looks for the sequence <!DOCTYPE HTML> at the start to make sure that it is reading an HTML file. All the HTML that describes the page is given between <html> and </html> tags. The </html> tag contains a lang attribute that specifies the language of the page. The language "en" is English. The <head> and </head> tags mark the start and end of the heading of the document. The heading contains information about the content of the page including styling information (which is discussed further in the next chapter). The text between the <body> and </body> tags is what is to be displayed. In other words, everything we have learned up to now goes into the body part of the web page file.

Linking HTML documents

An HTML document can contain elements that link to another document. The other document can be on the same server, or it can be on a different server entirely. A link is created by using an <a> tag, which has an href attribute that contains the URL of the destination page:

Click here to view code image

Click on <a href="otherpage.html">this link</a>to open another page.

The text in the body of the <a> tag is the text that the browser will highlight as the link. In the example HTML above the words “this link” will be the linkable text. This will result in text on the page that looks like this:

Click here to view code image

Click on this link to open another page.

If the reader clicks the link, the browser will open a local file—in this case, a file named “otherpage.html”—which will be displayed. The destination of the link can refer to a page on a completely different site:

Click here to view code image

<p>Click on <a href="https://www.robmiles.com"> this link</a> to go to my blog.</p>

Making active web pages

There are lots of other things that I could tell you about HTML. The language can be used to create numbered and unnumbered lists and tables. However, this is not a book about HTML; it is about programming. What we want is a way of getting JavaScript code to run inside a web page. Then we can start exploring the language.

You already know that a JavaScript program can sit alongside an HTML page design. You saw that in Chapter 1 when you used the developer view (obtained by pressing F12) in the browser to take look at the hidden program inside the hello.html web page. That HTML file contained a script element holding some JavaScript code. We used the console to run a JavaScript function. Now we are going to trigger a function by pressing a button.

Using a button

One way to create an active web page is by using a button. This HTML code creates a button that contains the text “Say Hello”:

Click here to view code image

<button onclick="doSayHello();">Say Hello</button>

The button is displayed in the normal flow of the text in the page, as shown in Figure 2-9.

Figure 2-9 Say Hello button

The button has an onclick attribute. One of the great things about JavaScript is that most of the time, the names make sense. The onclick attribute specifies a function that is to be used when the button is clicked. In this case, the attribute specifies a JavaScript function called “doSayHello”. A JavaScript function is a sequence of JavaScript statements that have been given a name. (We will take a detailed look at functions in Chapter 8.)

Click here to view code image

function doSayHello() {
  alert("Hello");
}

This function only performs a single action; it displays an alert that says “Hello” to the user when it is called. The line of JavaScript that displays the alert is called a statement. The end of a statement is marked by a semicolon character. A function can contain many statements, each of which is ended with a semicolon (;).

Click here to view code image

<!DOCTYPE html>
<html lang="en">
<head>
  <title>Ch02-06 Buttons</title>
</head>

<body>
  <h1>Buttons</h1>
  <p>
    <button onclick="doSayHello();">Say Hello</button>
  </p>

  <script>
    function doSayHello() {
      alert("Hello");
    }

  </script>

This is the complete HTML text of the web page. The <script> element is at the bottom of the body of the document. The page displays the Say Hello button, and when the button is pressed, the alert is displayed, as shown in Figure 2-10.

Figure 2-10 Say Hello alert

Reading input from a user

The button tag lets us create an element in a web page that responds to a user action. Next, we need a way of getting input from a user. The input tag lets us do just that:

Click here to view code image

<input type="text" id="alertText" value="Alert!">

It has three attributes:

type The type attribute tells the browser the type of input that is being read. In the code above, we are reading text, so the attribute type is set to text. If you set the type attribute to password, the contents of the input are replaced with other characters (usually * or .) as they are being typed in. This is how JavaScript programs read passwords in web pages.

id The id attribute gives an element a unique name. This name can be used in the JavaScript code to locate the element. If we had two input elements, we would use a different name for each. I’ve called the element alertText because this nicely reflects what the element is being used for.

value The value attribute specifies the value in this element tag. This is how we can prepopulate an input with text. When this input element is displayed, it will have the text “Alert!” in it. If we want the input to be blank when it is displayed, we can set the value to an empty string.

Click here to view code image

<p>
  <input type="text" id="alertInputText" value="Alert!">
  <button onclick="doShowAlert();">Show Alert</button>
</p>
<script>
  function doShowAlert() {
    var element = document.getElementById("alertInputText");
    alert(element.value);
  }
</script>

The web page contains the input element, a button element that will call a function to display the alert, and the function that uses the input text in an alert. The user can type their own text into the input and then press the Show Alert button to have the text displayed in an alert. Figure 2-11 shows what the program looks like when it is used.

Figure 2-11

If you run the example, you will notice that when you press the Show Alert button, the text you have entered in the input area is displayed in the alert.

HTML and JavaScript

It’s worth spending some time discovering how HTML and JavaScript work together, as this underpins almost all of the programs that we are going to write. The JavaScript program needs a way of interacting with the HTML document it is part of. This interaction is provided by methods, which are part of the document object model, or DOM, that the browser creates to represent the HTML document it is displaying for the user. The DOM is a software object that is held in the memory of the computer. The DOM contains methods alongside the HTML elements that make up the page. Our program uses the getElementByID method to get a reference to the element on the page. It then gets the text out of this element and displays that text in an alert.

If you’re not sure about this, perhaps an analogy would help. Think of the HTML document as “Rob’s Car Rental.” When someone comes to pick up a car, they will say, “I’ve come to pick up car registration ABC 123.” I will then hand them the keys and say “It’s over in bay E6”. They can then go find the car. I don’t hand the car to the customer over the counter because I’m not strong enough for that. I just tell them where the car is, so they can go and find it.

In the case of the HTML document, each of the elements in the document is like a car in the parking lot for my rental business. An element can be given an ID just like a car has a registration plate. In our document, the ID is alertInputText. The method getElementById is the means by which a JavaScript program can ask the document where an element is:

Click here to view code image

var element = document.getElementById("alertInputText");

On the right-hand side of the statement above, you can see the use of getElementByID to get the location of the text element with the alertInputText ID. The left-hand side of the statement creates a variable to hold this location. The word var creates a JavaScript variable. A variable is a named location that stores some information that the program wants to remember.

At “Rob’s Car Rental,” I would offer to write down the location of a car for a customer who was afraid of forgetting where their car was. I’d give them a piece of paper with “Car Location” (the name of the “variable”) and “Bay E6” (the value of the variable) written on it. In the JavaScript above, the variable we are creating is called element (because it refers to an element in the document) and the value is the location of the text input element. This operation is called an assignment because the program is assigning a value to a variable. An assignment operation is denoted using the equals (=) character. (We will discuss variables in detail in Chapter 4.)

Now that the program has a variable called element that contains a reference to the input, we can extract the text value from this element and store it in a variable called message:

var message = element.value;

The variable called message now contains the text that was typed into the input by the user. (Remember that we set this to “Alert!” in the HTML.) The program can now display this text in an alert:

alert(message);

It is very important that you understand what is going on here. Up until now, everything has seemed quite reasonable, and then suddenly, you’ve been hit with something really complicated. I’m sorry about that. Just go through the code and try to map the statements back to what the program is trying to do. And remember that the equals character (=) means “set this variable to the value.” It does not mean that the program is testing to see if one thing is equal to another.

If you are confused about how the various parts of the program fit together, consider that the program is doing exactly the same thing as if I had given a car rental customer the location of their car and then asked them to come back and tell me how much fuel there was in that car. That sequence would go as follows:

Get the location of the car.

Go to the car.

Get the value from the fuel-level display.

Bring that value back to me.

In the case of the JavaScript program that is displaying the message, the sequence is:

Use getElementById method to get a reference to the input element.

Follow the reference to the element.

Get the text value from the input element.

Display that text in an Alert.

CODE ANALYSIS

The doShowAlert function

Click here to view code image

function doShowAlert() {
  var element = document.getElementById("alertInputText");
  var message = element.value;
  alert(message);
}

We can build on our understanding of this important aspect of JavaScript by looking at this function and considering some questions.

Question: What would happen if you got the ID of the text element wrong?

Answer: The doShowAlert method uses an unspoken “contract” between the HTML and the JavaScript code. The doShowAlert function asks the getElementById to find an element with the alertInputText ID. If this contract is broken because the element has the wrong name, for example alertinputtext, the getElementById method will not be able to deliver a result. This is a bit like me telling a car rental customer to look for their car in a location that doesn’t exist. In this case, the getElementById method will return a special value called “null” which means “I couldn’t find anything.” This would cause the rest of the doShowAlert function to fail. In the case of my car rental customer, they would come back and tell me that the location does not exist. In the case of the doShowAlert function, there would be no error reported to the user, but the alert would not be displayed. Later in this book, we’ll look at how you can write code that will test for methods returning results that mean, “I couldn’t find what you wanted.”

In JavaScript, you tend to have to go hunting for the errors that you make. In some programming languages, you are told about errors when they occur. In JavaScript, things tend to fail silently or just do something that you were not expecting.

Question: What would happen if the user didn’t type any text into the text area on the web page before pressing the button?

Answer: If you look at the HTML at the very start of this section, you will see that the value attribute of the text tag is set to “Alert!” If the user doesn’t replace this with their message the word “Alert!” will be displayed.

Question: What would happen if I pressed the button several times?

Answer: The browser will block any activity on the web page until you clear the alert that is displayed. When you press the button again, the doShowAlert function would be called again. It would make two new variables called element and message and use them to display the appropriate message text.

Question: What does var do?

Answer: The word var is a command to JavaScript to create a variable. The name of the variable follows the word var. The variable holds a value that the program wants to make use of. A program can assign values to variables by using = to tell JavaScript to perform an assignment.

Display text output

In the previous section, we used a JavaScript program to read data from a web page by getting a reference to an element on the page and then reading information from that element. Displaying text on the screen is a similar process. A JavaScript program can use a reference to an object to change attributes of the element. We are going to write a program that changes the text in a paragraph into a string of text that we have entered. The complete HTML file looks like this:

This example is an extension of the previous one. Instead of displaying text using an alert, this example sets the textContent attribute of a paragraph to the text that the user enters into the dialog box. The behavior of this program is given in four lines.

Click here to view code image

      var inputElement = document.getElementById("inputText");
      var outputElement = document.getElementById("outputParagraph");
      var message = inputElement.value;
      outputElement.textContent = message;

The first two lines set up variables that refer to the input and output elements. The third line gets the message to be displayed, and the fourth puts this message onto the web page, as shown in Figure 2-12.

Figure 2-12 Paragraph Update message

MAKE SOMETHING HAPPEN

Work with object properties

You might be wondering what the textContent property does and how the program uses it, so it might be worth investigating this. We can use the JavaScript console in the Developer Tools to do this. Find the folder on your PC that contains the sample code for the book. (If you haven’t downloaded the sample code, you can find the instructions in Chapter 1 in the “Getting the sample files” section.) Find the Ch02 HTML/Ch02-08 Paragraph Update folder. Double-click the index.html file in that folder. This should open your browser, and you should see a page that looks like the one in Figure 2-12 above.

Note that Edge will only open if it is the default browser on your computer. On a Windows PC, you can select which browser should open a page by right-clicking the page and then selecting Open With from the menu that appears. Once the page is open, do the following:

Press F12 to open the Developer Tools view. Select the Console tab. Enter the following JavaScript statement:

Click here to view code image

var outputElement = document.getElementById("outputParagraph");

This is the statement in our program that gets a reference to the outputParagraph in the document. We now have a variable called outputElement that refers to the output paragraph. We can prove this by using our new variable.

Click here to view code image

outputElement.textContent = "fred";

Take a look back at the web page. You should see that the word “fred” has appeared. By setting the value of the TextContent property of the paragraph, we can change the text in the paragraph. A JavaScript program can read properties as well as write them. Enter the following statement:

Click here to view code image

alert(outputElement.textContent);

This will make an alert box appear with “fred” in it (because that is the textContent of the element referred to by outputElement). Now let’s see what happens if we make a mistake. Try this:

Click here to view code image

outputElement.tetContent="test";

This statement looks sensible, but I’ve mistyped “textContent” as “tetContent.” The paragraph element does not have a tetContent property. However, this statement doesn’t cause an error, but the word “test” is not displayed either. What happens is that JavaScript creates a new property for the outputElement variable. The new property is called “tetContent” and it is set to the value “test.” You can prove this by entering the following:

Click here to view code image

alert(outputElement.tetContent);

This will display an alert showing the value in the tetContent property, which is the string “test.” We will discover more about creating properties in objects in Chapter 9.

See if you can change the web page so that the name is displayed as a heading (<h1>) rather than as a paragraph. You can use Visual Studio Code to edit the HTML for the web page. Will you have to change the JavaScript or the HTML?

Egg timer

We now know enough to be able to create a properly useful program. We are going to create an egg timer. The user will press a button and then be told when five minutes (the perfect time for a boiled egg) have elapsed. We know how to connect a JavaScript function to an HTML button. The next thing we need to know is how to measure the passage of time. We can do this by using a JavaScript function called setTimeout. We have used functions already. The alert function accepts a string that it displays. The setTimeout function accepts two things: a function that will be called when the timer expires and the length of the timeout. The timeout length is given in thousandths of a second. The statement below will cause the doEndTimer function to run one second after setTimout was called.

setTimeout(doEndTimer,1000);

Our egg timer will use two functions. One function will run when the user presses a button to start the timer. This function will set a timer that will run the second function after five minutes. The second function will display an alert that indicates that the timer has completed.

Click here to view code image

function doStartTimer() {
  setTimeout(doEndTimer,5*60*1000);
}

function doEndTimer() {
  alert("Your egg is ready");
}

The doStartTimer function is connected to a button so that the user can start the timer. The doEndTimer will be called when the timer completes. I’ve added a calculation that works out the delay value. I want a five-minute delay. There are 60 seconds in a minute and a value of 1000 would give me a one-second delay. This makes it easier to change the delay. If we want to make a hard-boiled egg that takes seven minutes, I just have to change the 5 to a 7. Note that the * character is used in JavaScript to mean multiply. You will find out more about doing calculations in Chapter 4.

MAKE SOMETHING HAPPEN

Investigate the egg timer

Click here to view code image

<!DOCTYPE html>
<html lang="en">
<head>
  <title>Ch02-09 Egg Timer</title>
</head>

<body>
  <h1>Egg Timer</h1>
  <p>
    <button onclick="doStartTimer();">Start the timer</button>
  </p>

  <script>
    function doStartTimer() {
      setTimeout(doEndTimer,5*60*1000);
    }

    function doEndTimer() {
      alert("Your egg is ready");
    }
  </script>
</body>
</html>

Let’s take a look at how the egg timer works. Find the Ch02 HTML/Ch02-09 Egg Timer folder. Double-click the file index.html in that folder to open the page.

Click the Start The Timer button once. This version of the code only has a 10-second delay, so after 10 seconds, you would see the alert appear.

Click the Start The Timer button three times in succession. Wait and see what happens. Was this what you expected? It turns out that each time you press the button, a new timeout is created. Now press F12 to open the Developer Tools. Enter the following code and press Enter. What would you expect to see?

doEndTimer();

This is a call of the function that will run and display the end message. You should see the alert appear telling you that your egg is ready. Click OK in the alert to close it. Enter the following and press enter. What would you expect to happen?

setTimeout(doEndTimer,3*1000);

After three seconds the alert appears, because that is the length of the timeout. You should also have seen something else appear when the function runs. You will also see an integer displayed. If you repeat the setTimeout call, you will see another value displayed. It is usually one bigger than the previous one. This number is the “ID” of timer. This can be used to identify a timeout so that it can be canceled. We are not going to do that, so you can ignore this value.

See if you can change the web page so that it supports multiple cooking times. Add buttons for “Soft” (four minutes), “Normal” (five minutes), and “Bullet” (ten minutes). You will have to add two more buttons and two more JavaScript functions to the program.

If you want to see how I did it, open the Ch02-09 Selectable Egg Timer file. My solution even displays the status of the timer.

Adding sound to the egg timer

Our egg timer works fine, but it would be nice if it could do a little more than just display an alert when our egg is ready. A web page can contain an audio element that can be used to play sounds.

Click here to view code image

<audio id="alarmAudio">
  <source src="everythingSound.mp3" type="audio/mpeg">
  Your browser does not support the audio element.
</audio>

The audio element includes another element called src that specifies where the audio data is going to come from. In this case, the audio is stored in an MP3 file named everythingSound.mp3, which is stored on the server. The text inside the audio element is displayed if the browser does not support the audio element. I’ve given this element an ID so that the code in the doEndTimer function can find the audio element and ask it to play the MP3 file.

Click here to view code image

function doEndTimer() {
  alarmSoundElement = document.getElementById("alarmAudio");
  alarmSoundElement.play();
}

This code looks like the code in the Ch02-08 Paragraph Update example. In that case, the getElementById method was fetching a paragraph element to be updated. In the function above, getElementById is fetching an audio element to be played. An audio element provides a play method that starts it playing. The rest of the file is exactly the same as the original egg timer. If you try this program, you will hear quite an impressive sound when your egg is ready.

Controlling audio playback

The egg timer page does not display anything to represent the audio element. It is “hidden” inside the HTML. You can modify an audio element so that a player control is shown on the web page. To do this, you just have to add the word controls into the element tag:

Click here to view code image

<!DOCTYPE html>
<html lang="en">

<head>
  <title>Ch02-11 Sound playback</title>
</head>

<body>
    <audio controls>
        <source src="everythingSound.mp3" type="audio/mpeg">
      Your browser does not support the audio element.
    </audio>
    </body>
</html>

This is the complete source of an MP3 file playback page. If you visit the page you will see a simple playback control, as shown in Figure 2-13.

Figure 2-13 Sound playback

This is how the playback control looks when using the Edge browser. Other browsers will look slightly different, but the fundamental controls will be the same. You can start the playback by pressing the play control at the far left.

An image display program

The final example program in this chapter shows how JavaScript can change the content of an image displayed on the screen. You can use this technique to implement “slide shows” and also allow the user to select images for display. The image to be updated must be given an ID:

Click here to view code image

    <img src="seaside1.JPG" id="pageImage"></p>

This img element displays the picture in the file seaside.JPG. A JavaScript program can change the displayed image by modifying the src attribute of the image and making it refer to a different image file:

Click here to view code image

var pic = document.getElementById("pageImage");
pic.src="fairground.JPG";

These two statements get a reference to the image and then set the src attribute of the img to refer to the image fairground.jpg. This will update the image displayed by the browser. Note that this is a repetition of a pattern that you’ve seen several times now. A program obtains a reference to a display element and then makes changes to it. You can find a complete image picker program in the Ch02-12 Image Picker example.

MAKE SOMETHING HAPPEN

Create your own pages

You now know enough to create your own pages that contain timers, images, and buttons. Here are some ideas for you to think about:

Make a “mood” page The page will display buttons labeled “Happy,” “Sad,” “Worried,” and so on. When the user presses a button, the page will display an appropriate message and play a piece of appropriate music.

Make a “fitness” page Users will press a button to select an exercise length, and the page will display exercise instructions and start a timer for that exercise.

Make a slide show Users press a button, and the page will show a sequence of images. To do this, you can use a number of calls to setTimeout to trigger picture changes at different times in the future—perhaps one at two minutes, one at four minutes, and so on.

What you have learned

This chapter has given you a good understanding of what the World Wide Web is and how it works. Here are the major points you’ve covered in this chapter:

The HTTP (Hypertext Transport Protocol) is used by browsers to request pages of data from web servers.

Data arriving at the browser is formatted using HTML (Hypertext Markup Language) and a web page contains commands to the browser (for example emphasize this word) using tags (for example, <em>) to mark out elements in the text. Elements can contain text, images, audio, and preformatted text. Elements can also contain links to other web pages, which can be local to a page or on distant servers.

HTML text can contain symbol definitions. Symbols include characters such as < (less than) and > (greater than), which are used to mark tags and can also be used to incorporate emojis into web pages.

An HMTL document comprises a line that identifies the document as HTML, followed by header and body elements enclosed in an HTML element. The body of the document can contain a <script> element that holds JavaScript code.

A web page can contain a button element that runs a JavaScript function when the button is activated.

JavaScript code interacts with the HTML document via a document object containing all the elements of the page. The document provides methods that a program can call to interact with it. The document method getElementById can be used to obtain a reference to the page element with a particular ID.

A JavaScript program can contain variables. These are named storage locations. A variable can be assigned a value, which it will store for later use. The assignment operation is denoted by the equals (=) character.

A JavaScript function can locate elements in a document by their id attribute and then use element behaviors to change the attributes on the elements. This is how a JavaScript program could update the text in a paragraph or change the source file for an image.

The setTimeout method can be used to call a JavaScript function at a given time in the future.

To reinforce your understanding of this chapter, you might want to consider the following “profound questions” about JavaScript, computers, programs, and programming.

What is the difference between the Internet and the World Wide Web?

The Internet is a mechanism for connecting large numbers of computers together. The World Wide Web is just one thing that we can use the Internet for. If the Internet were a railway, the World Wide Web would be one type of passenger train providing a particular service to customers.

What is the difference between HTML and HTTP?

HTTP is the Hypertext Transport Protocol. This is used to structure the conversation between a web browser and a web server. The browser uses HTTP to ask, “Get me a page.” The server then gives a response, along with the page if it is found. The format of the question and the response is defined by HTTP. The design of the content of the page is expressed using Hypertext Markup Language. This tells the browser things like “put a picture here” or “make this part of the text a paragraph.”

What is a URL?

A URL is the address of a resource that a browser wants to read. It starts with something that identifies what kind of thing is being requested. If it starts with HTTP, it means that the browser would like a web page. The middle part of the URL is the network address of the server that holds the web page to be read. The final part of the URL is the address on the server of the web page. This is a path to a file. If the path is omitted, the server will return the contents of a default file, which is sometimes (but not always) the file index.html

Where do I put things like image and audio files when I build a website?

The simplest place to put images and audio files is in the same folder as the website. So, the folder that contains index.html can also contain these images and sounds. However, a path to a resource can include folders, so it is possible to organize a website so all the images and sound files are held separately from the web pages. We will do this in the next chapter.

Why should I not use preformatted text for all my web pages?

The <pre>..</pre> element allows page designers to tell the browser that a block of text has already been formatted and that the browser is not to perform any additional layout. This can be useful for displaying such things as program listings that have a fixed format, but it does not allow the browser to make any allowance for the target device. One of the fundamentals of web page design is that the browser should be responsible for laying out the page. The page itself should contain hints such as “take a new paragraph here” and allow the browser to sort out the final appearance.

Why should I use <em> rather than <i>?

The <i> (italic) tag means “use italic text.” The <em> tag means “make this text stand out.” If the browser is running on a device that does not support italic text, it is much more useful for it to be asked to emphasize text (which it could do by changing color or inverting black and white), rather than select a character type that it is not able to display.

How are HTML tags and elements related?

A tag is the <p> marker that denotes that this text is an instruction to the browser rather than something to be displayed on a page. A complete sequence of tags (perhaps with a start and end tag) marks a complete element in a web page.

Does every HTML tag have to have a start and an end element?

No. Lots of tags do. For example, <p> marks the start of a paragraph and </p> marks the end. But some, for example <br> (create a new line), do not.

Can you put one element inside another?

Yes. A paragraph element may contain elements of emphasized text. And an audio element contains an element that identifies the source of the audio to be played.

What is the difference between an attribute and a property?

The HTML source of a web page contains elements with attributes. For example, <img src="seaside1.JPG"> would create an image element with a src attribute set to the image in the seaside1.JPG file. Within JavaScript, the web page the program is part of is represented by a document object that contains a collection of objects. Each object represents one of the elements on the page. Each element object has a property that maps to a particular page attribute. A JavaScript program could change the src attribute of an image element to make it display a different picture. In short, attributes are the original values that are set in the HTML, and properties are the representations of these values that can be manipulated in a JavaScript program.

What is a reference?

In real life, a reference can be something that you follow to get somewhere. In a JavaScript program, a reference is used by a program to find a particular object. An object is a collection of data and behaviors that represent something our program is working with. JavaScript uses objects to represent elements on a web page. Each element is represented by an object. A reference is a lump of data that holds the location of a particular object.

What is the difference between a function and a method?

JavaScript contains functions, which are blocks of JavaScript code that have a name. We have written functions with names like doEndTimer. Methods are functions that are held inside objects. We have used the getElementById method, which is provided by the document object.

3
Cascading Style Sheets (CSS)

What you will learn

In the last two chapters, you’ve learned how to use HTML to design a web page and how to use JavaScript to add some behaviors to it. However, you’ve probably also noticed that the web pages that you’ve been creating don’t look much like ones on the sites you usually visit. They are lacking in design and color. In this chapter, you’ll discover how to manage the appearance of a web page to make it more appealing. Along the way, you’ll pick up some important points abut JavaScript programming and make some nifty applications and games.

Putting on the style

Color highlighting on mouse rollover

Get the time for display

Exploring style sheets

Cascading styles

What you have learned

Putting on the style

We can start by considering what style is. Apparently, it is something that you either have or have not got. And I’ve been told many times that I don’t have any. But in the case of web page design, I have a little bit, and I can tell you how to create and apply styles to the contents of web pages. The style of an element on a web page covers such things as the foreground and background color it has, the type of character design (font), the size of the text, and things like margins. You can think of a style as a collection of settings that you want to apply to something. We are going to start by styling some text. Once we’ve worked out how to apply style to a single element in a document, we will move on to consider how we can make it easier for us to change the style of all the elements in a document.

Splashing some color

We can start by adding a bit of color to a page. The definition of an HTML element on a web page can contain attributes that describe the element. We can add a style attribute to an element to set the foreground color for that element.

Click here to view code image

<p>This is an ordinary paragraph</p>
<p style="color:red">This is a red paragraph.</p>

Above, you can see how style is applied to a single paragraph. The first paragraph is ordinary. The second has been styled with red text. Figure 3-1 shows how this appears on the page.

Figure 3-1 Styling text

The HTML standard contains a set of color definitions that you can refer to by name. Visual Studio Code will show you a tiny preview of the color when you are editing the text of your code, as shown in Figure 3-2.

Figure 3-2 Visual Studio color preview

Visual Studio Code will also produce a color menu when you start typing a color value into a style when you are editing your HTML source (see Figure 3-3).

Figure 3-3 Visual Studio color selector

There are very many style settings. The interactive help in Visual Studio will show you all the possible settings when you start typing a style command. Style settings can be combined in a single style description by separating them with the semicolon character. The style below would result in a tasteful display of red text on a yellow background.

Click here to view code image

<p style="color:red; background: yellow;">Red on Yellow.</p>

MAKE SOMETHING HAPPEN

Color highlighting on mouse rollover

By now you should be used to a pattern of JavaScript program that works like this:

Attach a JavaScript function to an event.

When the function runs, it gets a reference to an element in the document.

The function then changes a property on the element to change the appearance of the document.

We’ve used this to make a program that responds to button clicks and another one that runs a function after a time interval has elapsed. Now we are going to use exactly same pattern to make a web page that highlights text when you roll the mouse over it. You definitely seen this used on web pages that you have visited. Take a look at the code below:

Click here to view code image

<!DOCTYPE html>
<html lang="en">
<head>
<title>Ch03-02 Color Change on Mouse Over</title>
</head>
<body>
<p onmouseover="doMouseOver();" id="mouseOverPar">Roll your mouse over this paragraph.</p>
<script>
    function doMouseOver()
    {
        var par = document.getElementById("mouseOverPar");
        par.style="color: red";
    }
</script>
</body>
</html>

Can you work out which event we are using, and how the function doMouseOver changes the color of the text?

The event that we are using is called onmouseover and the program is using the style property of the paragraph to make it turn red. The browser will call the function doMouseOver when it detects that the mouse pointer is over the paragraph text. The function doMouseOver obtains a reference to the paragraph and then sets the style of that paragraph to include the color red.

Let’s take a look at how the code works in practice. Find the Ch03 HTML/ Ch03-02 Color Change on Mouse Over folder. Double-click the index.html file in that folder to open the page. In the top-left corner, you will see a simple page with this message: “Roll your mouse over this paragraph.” Roll your mouse over the text and note what happens. You should see the text turn red, which is exactly what you want, but you should notice something else, too. Is the behavior what you want? I think you would prefer it if the text turned back to black when the mouse was not over the paragraph.

We have found our first bug. A bug in a program is a behavior that you don’t want. Finding and fixing bugs is a big chunk of software development. In this case, the bug came about because we didn’t think through what rollover actually means. Perhaps we assumed that the browser would restore the original color of the text when the mouse left the paragraph, but that is not how the program works. How do you think we can fix this?

We can fix it by using another event. It turns out that an element on a web page can generate events when a mouse leaves it as well as when the mouse moves over it. The event that we need to use is called onmouseout, and we need to connect it to a function that sets the text color of the paragraph back to black. See if you can fix your copy of the program so that it works correctly. Edit the index.html file using Visual Studio Code, save it, and then test it with the browser.

If you want to see my fixed solution, take a look in the Ch03 HTML/ Ch03-03 Color Change on Mouse Over Working folder. This works, but later in the text, we will discover a much easier way to create a rollover effect.

PROGRAMMER’S POINT

Bugs are a fact of life for a programmer

You are going to have to get used to creating bugs. I’ve been programming for many years and I still write code with bugs in. And I expect to create many more bugs as I write more programs. The thing to remember is that creating a bug is fine, but creating a fault is not. You get a fault when a customer finds a bug in your program. Programmers spot bugs by testing. Programmers make faults by not testing enough, which leads to bugs making their way into the final product. Whenever you make something, you need to work out how to test it. In the case of our “paragraph highlight” program, the testing is obvious—just move the mouse over and see what happens. When we make some bigger programs, we’ll discover that testing can be more complex.

Note that bugs are also the result of by poor specifications. Initially, I said that I wanted some text to change color when the mouse pointer is rolled over it. The first version of our program did this, so you could say it was free of bugs. It was only when we noticed that the text stayed highlighted when the mouse moved off the text that we decided that behavior was not what we wanted. This shows how important it is to think through exactly what you want a program to do before you start building it. It also shows the usefulness of “prototype” programs that can be used to determine whether the solution does exactly what the customer wants.

Work with fonts

Fonts are one of many things about computers where computer manufacturers have “agreed to differ.”

They all agree that they need a font that looks like this.

(This is called a serif font because the lines in the character design have lines on the end.)

And they all agree that we need a font that looks like this.

(This is called a sans-serif font because it doesn’t have extra lines and “sans” is French for “without.”)

However, the manufacturers have not agreed on the names for them. For example, the “sans serif” font can be called “Arial” or “Helvetica.”

Select a text font

This means that when we specify the font to use in a web page, we can’t request a specific font because we don’t know what type of computer is being used to view the page. Instead, we will specify a font family. This is specified in the style for an element. We can specify a list of fonts that we would like to use, and the browser will work through them in order looking for a font that it can use:

Click here to view code image

<p style="font-family:Arial, Helvetica, sans-serif">This is in sans-serif font</p>

The style above asks for Arial, followed by Helvetica and finally sans-serif. Most computers have a sans-serif font, so the last entry in the list acts as a “catch all.” The first item on the list is a specific font, while the last item on the list will be a more abstract font type. If I were picking vegetables to have for dinner, the first item would be “chips” (a specific dish) and the last would be “potatoes” (a general catch-all for the particular vegetable I want). Font selection works in the same way. Note that when I select a font family, I get the designs for bold and italic versions of the characters in that font, too. See Figure 3-4.

Figure 3-4 Visual Studio Code font selector

We have already seen how helpful Visual Studio Code is when selecting style colors. It also pops up suggestions for font families, which have been arranged in a sensible way. The suggested families give a good range of typefaces that you can use in your pages, as shown in Figure 3-5 below. You can find the HTML code that generates this page in the example folder at Ch03 HTML/ Ch03-04 Fonts in JavaScript.

Figure 3-5 Font examples

WHAT COULD GO WRONG

Fonts can be a minefield

I must admit that I find it difficult to spot the difference between the Cambria and Georgia fonts in Figure 3.5 above. But some people can, and they may have strong opinions. Make sure that you agree with your customer about the fonts that you are going to use. I don’t use many fonts in my pages. I usually use one serif font for headings and a sans-serif for normal text (or vice versa). Just because you can use lots of fonts in a page doesn’t mean that you should.

You should make sure that if a font name contains spaces (for example, Times New Roman), you should enclose this name in single quotes in the font family setting. You should also note from Figure 3.5 above that different fonts have quite different sizes, which can affect your page layout.

Select a font size

As I write this book, I’m not really worrying too much about the particular font size of the text. I know that the headings must be larger than “normal” text, but I don’t concern myself too much with specific dimensions. When designing web pages, you should take a similar approach. In other words, if you want to display large text in a heading, select the H1 format for the heading, and don’t change the size of the font in the heading.

If you want to specify the size of text in a web page, there are a number of units you can use. You can express the size in inches, centimeters, pixels, points, or as a percentage of the size of the display, but I would advise you to use the em unit. An em value of 1 means normal-sized text. If you want smaller text, use a value of em that is smaller than 1; for example, an em value of 0.5 would mean half the normal size. This makes all the font sizes relative rather than absolute. This is usually what you want. As the creator of a page, you want to make sure that the text will be readable on all devices. Setting an absolute size will make text that looks perfect on one device and wrong on every other. If you want text twice as big as the normal size for that font, you would set the em size to 2 and so on. You set the size of the text on the screen by setting a font-size in a style:

Click here to view code image

<p>This is normal text.</p>
<p style="font-size:1em">This is 1 em.</p>
<p style="font-size:2em">This is 2 em.</p>
<p style="font-size:0.5em">This is 0.5 em.</p>

Figure 3-6 shows the above HTML as it would appear on the page. (You can find the HTML code that shows these examples in Ch03 HTML/Ch03-05 Font Sizes.)

Figure 3-6 Font sizes

Text alignment

You can also add an element to a style command to tell the browser how to lay out the text. By default (unless you specify otherwise), your text will be laid out with each line starting at the left-hand margin. You can add a text-align setting to a style, as shown below and in Figure 3-7.

Click here to view code image

<p style="text-align: left;">This text is aligned at the left hand margin of the page and the words
    will wrap with a ragged edge.
    This is the normal format of text</p>
<p style="text-align: center;">This text is aligned in the center.
    Useful for headings and quotations.</p>
<p style="text-align: right;">This text is aligned at the right margin of the page.</p>
<p style="text-align:justify;">This text is aligned at the left and right margins of the page.
    This makes the text look like the pages of a book or a column in a newspaper.</p>

Figure 3-7 Text alignment

Make a ticking clock

We can use our ability to display large text on the screen to create a large ticking clock. However, to do this we need to know how a JavaScript program can obtain the current time (the value of hours, minutes, and seconds to be displayed by the clock). We also need to create a program that runs every second to update the clock display.

MAKE SOMETHING HAPPEN

Get the time for display

The programs that we have created so far have interacted with the Document object, which represents the HTML that makes up the web page. To get the time, we need to create another type of object, the Date object. Let’s see how this works. Find the Ch03 HTML/ Ch03-07 Clock Display folder and double-click the index.html file in that folder to open the page. You should see a clock displaying 0:0:0. We are going to get the time and display it on the clock. Press F12 to open the Developer Tools view and move to the console window. Enter the following JavaScript statement:

var currentDate = new Date();

We’ve seen var before; it is how a program creates variables. The variable that is created is called currentDate and it is made to refer to a newly created Date object. The word new means “make a new object.” We’ve not had to create any objects before because our programs have used objects that already exist when the program runs. The Date object is provided to allow JavaScript programs to work with dates and times.

When a new Date object is created, it is set with the current date and time. The variable currentDate is a reference that refers to the newly created Date object. We’ve used references before when we created a reference to a paragraph element in a web page that we wanted to update. Take a look at example Ch02-08 Paragraph Update if you need to refresh your understanding of this. We can ask an object questions by calling methods on the reference to it. Type the following:

alert(currentDate.getHours());

This statement uses the getHours method, which is part of a Date object. This method returns a number that contains the hours value of the date. The statement displays this in an alert. There are also methods to get the minutes and seconds values. Each method has a name that reflects what it does. See if you can use them to display these time values as well. Note that you must put the open and close brackets () after each method name so that JavaScript knows you want to call the method. We will find out more about making method calls in Chapter 7.

Now type in the following statements to set variables with the hours, minutes, and seconds values that we need for the clock:

Click here to view code image

var hours = currentDate.getHours();
var mins = currentDate.getMinutes();
var secs = currentDate.getSeconds();

We now have the hours, mins, and secs variables that we can use to build up a string to display as the time. The string will contain the time values separated by the : (colon) character. Type the following statement to create the time string:

Click here to view code image

var timeString = hours+":"+mins+":"+secs;

This statement creates a variable called timeString that contains the time that we want to display. The values in the hours, mins, and secs variables are converted into text. You can view this string using an alert:

alert(timeString);

If you check the time that appears in the alert, you will find that it is out of date because it will have taken you a few seconds to type all these statements. The value in currentDate is a snapshot of the date and time. This will not be a problem in our clock program because the time values will be displayed immediately after they have been read. We now know how to get the time value into a string that is ready for display. The HTML for the clock display program contains a paragraph that has the id timePar. Type the following statements:

Click here to view code image

var outputElement = document.getElementById("timePar");
outputElement.textContent=timeString;

We’ve used this pattern of statements before. The first one creates a variable that refers to the output element we want to use to display the time. The second statement sets the textContent property of that element to the contents of the timeString variable. This will cause the time to be displayed.

The HTML for this page contains a function that does everything we have just typed in. Type the following statement to call this function:

doClockTick()

You should see the date and time update to show the current date and time. Press F12 to close the Developer Tools in the browser.

Create a ticking clock

We now know how to create a string that contains the current time and then display that string in large text. Now we need a way to make the clock “tick.” When we created the egg timer programs in Chapter 2, we used a function called setTimeout to call a JavaScript function after a specified timeout value. Another useful function in JavaScript is called setInterval, which calls a function at regular intervals. As with the setTimeout function, the interval is specified in milliseconds.

setInterval(doClockTick,1000);

The statement above would cause a method called doClockTick to be called every second. This is the function that will update our clock. The final piece of our application is a way of starting the interval timer. We could ask the user to press a button to start the clock (this is how the egg timer works), but it would be best if the clock starts ticking as soon as the page is opened. The onload event can be made to call a function when an element on a web page is loaded—in this case, a three-digit ticking clock, which is shown in Figure 3-8. You can find the HTML code below in the Ch03 HTML/ Ch03-08 Ticking Clock example folder.

Figure 3-8 Ticking clock

CODE ANALYSIS

Ticking clock

You might have some questions about this code. And if you haven’t, I have. It’s important that you understand the answers because they underpin some important aspects of JavaScript programming.

Question: What is the difference between var and new?

Answer: The commands var and new look very similar because they seem to be associated with the creation of something, but you might be confused about exactly what is going on. In the case of var, a program is creating a new variable:

var age=21;

This would create a variable called age, which is set to the number 21 (which is a bit optimistic in my case).

Click here to view code image

var outputElement = document.getElementById("timePar");

This would create a variable called outputElement, which is set to the result delivered by the getElementByID from the document object. (You can refresh your understanding of how this works by reading the section “HTML and JavaScript” in Chapter 2.) So, every time we want to create a variable (such as a named location into which we can store something), we use var. In the next chapter, we will consider variables in much more detail.

A program uses new when it wants to make a new object. The word new is followed by the name of the type of object that is to be created:

Click here to view code image

var currentDate = new Date();

This creates a new variable called currentDate (that’s what var does) and then sets this variable to refer to a Date object created using new. So, var is used to create variables, and new is used to create objects.

Question: Do I have to put semicolons after each statement when I use the console?

Answer: You might have noticed that console commands still work if you leave off the semicolon at the end. When you type JavaScript statements into the console, you end each one by pressing the Enter key. This means that JavaScript knows when you have finished the statement because you have pressed Enter. However, if you wanted to enter multiple statements on one command line, you would have to separate them using the semicolon character. I like to always add a semicolon so that someone reading my code will know exactly when I intend to end my statements.

Question: Why is one function name enclosed in quotes, whereas the other is not?

Answer: The clock program uses two functions. One is called doStartClock and starts the clock running. The other function is called doClockTick and updates the clock every second. The function doStartClock is called when the page is loaded by using the onload attribute of the body element:

Click here to view code image

<body onload="doStartClock();">

The doClockTick function is called every second using the setInterval function:

Click here to view code image

setInterval(doClockTick, 1000);

You might be wondering why the name of doStartClock is enclosed in double quotes, whereas doClockTick is not. At least, I hope you are, because appreciating the distinction will help you a lot in understanding how JavaScript and HTML work together. In the case of the onload event in the HTML, the action to be performed is a string containing JavaScript statements that are obeyed when the element is loaded. The string that we are using calls the doStartClock method, but it could be any sequence of JavaScript statements:

Click here to view code image

<body onload="var x=99;alert(x);">

This is completely legal HTML. The JavaScript that is performed on loading creates a variable called x, sets the value to 99, and then displays an alert showing this value. However, the setInterval function is given a reference to a function to be called every second, not a string containing some JavaScript code. You might be wondering why these two things work in different ways. This is because the onload event is part of an HTML element, whereas the setInterval function is called from within the JavaScript program code.

Question: Why does the time take a second to appear when the clock starts?

Answer: If you load the example, page you will find that it takes a second for the time to appear. For a second after the page has loaded, the time is displayed as 0:0:0. If you think about it, this is exactly how the program works. The setInterval function calls the function doClockTick at one-second intervals, but this means that program must wait for this interval to elapse before the clock is displayed. Can you think of a way to solve this problem?

The solution is simple. The program must call doClockTick from the doStartClock function. Since the doStartClock method is called when the page is loaded, this will cause the display to be updated at the start. You can find my version of this in the Ch03 HTML/Ch03-09 Clock Quick Start folder.

Margins around text

Text on a printed page does not extend right to the edge of the paper. This book has margins around the paragraphs. Some paragraphs (for example, the “Code Analysis” sidebar above) have different margins from the rest of the text. This makes the paragraphs stand out. A style can express the size of margins around a paragraph. It can also describe a border for a paragraph. The paragraph above has an outer margin, a border, and then “padding” around the text inside the border.

Click here to view code image

<p style="margin: 20px;
    padding: 10px;
    border:1px;border-style: solid; border-color:blue;">
    This is some text in a blue box.</p>

The dimensions of the margins and the border are expressed in units we have not seen before called px, which is short for pixel.

I could have spent some time drawing a diagram to show how the margin, border, and padding values are used to control the layout of text on a page, but it turns out that the Edge browser will do this for me. In Figure 3-9, you can see the developer view of the HTML above, which you can find in the code folder Ch03 HTML/ Ch03-10 Margins. The diagram on the bottom right of Figure 3-9 shows how the margin, border, and padding elements all fit inside each other.

Figure 3-9 Margin display

I’ve specified the margin, border, and padding dimensions in the px unit, which is an absolute unit that equates to a single dot on the target display. We used these units when we specified the size of an image to be drawn on the screen. If you are concerned with precise layout, you can use these to lay out text and graphics exactly. The size of a px unit matches that used to set the size of images, so you can combine text and graphics to make precisely aligned pages. The HTML below, which you can find in the Ch03 HTML/ Ch03-11 Fixed Width Paragraphs code folder, puts an image and a descriptive paragraph inside a blue box, as shown in Figure 3-10 below.

Click here to view code image

<p style="margin: 20px;
    border:1px;
    border-style: solid;
    border-color:blue;
    padding: 10px;
    width:400px;
    font-family: Arial, Helvetica, sans-serif;
    text-align: justify;
    ">
    <img src="seaside.JPG" alt="Waves crashing on a deserted beach" width="400">
    This picture was taken on New Year&quot;s Day 2020 at Hornsea sea front.
    Hornsea is a village on the north eastern coast of England.</p>

Figure 3-10 Text and graphics

There are lots more things you can do with styles. The best way to find out about them is to use the pop-up help in Visual Studio Code to get ideas for command options and then try them out.

Making a style sheet

An HTML document can use the style attribute to add style to any element in a document. However, it seems like hard work to have to add style elements to everything. Fortunately, HTML provides a way to simplify the application of a style to a document. We can add a style sheet to an HTML document to apply styles to elements in the document. The style sheet is added to the head of the document between the <style> and </style> tags, as shown below.

We can use a style sheet to set style properties on elements. A style setting starts with a selector, which specifies the element that is being styled. We want to style the <p> element, so that is what we specified in the style sheet above. The changes the style sheet makes result in all <p> elements in the document being displayed in blue text using the Arial, Helvetica, or sans-serif fonts. A style sheet can provide style settings for many elements.

Creating a style sheet file

When a website is created the designers usually come up with a standard “house style” which is to be applied to all the pages. The house style settings could be included in the <head> section of each page as shown in the sample above, but this would make it hard to change the style of the site because each document would need to be edited. To make this easier the style settings can be stored in a separate file. A <link> element in the HTML header then specifies the style sheet file to be added.

Click here to view code image

<head>
    <title>Ch03-13 Stylesheet File</title>
    <link rel="stylesheet" href="styles.css">
</head>

The HTML above shows how this works. The link element contains a rel attribute that tells the browser the type of resource that the link relates to. In this case, the link relates to a style sheet. The link to the file containing the style information is specified in the href attribute. In the case of the HTML page above, this is a local file called styles.css, which is held in the same folder as the HTML page. However, this file could be in a different folder, or it could even be on another server. The actual style sheet file contains the style instructions:

Click here to view code image

p {
    color: blue;
    font-family:Arial, Helvetica, sans-serif;
}

PROGRAMMER’S POINT

It is a good idea to separate style from layout

A web page is made up of layout (what is on the page and where it is) and style (how the page looks). It is very sensible to separate these elements. I could have filled this entire book with a description of how to style web pages, but it would not be a very good read because I’m not very good at design. I’d much rather find a designer who is good with fonts and colors and ask them to sort those things out. Being able to put the styling information into a separate file means that I can design the layout and the behavior of the application entirely apart from the style.

Computer scientists talk about “separation of concerns” in a project, where different people work on different parts. At the start of the project, everyone agrees how the different components will work together, and then they can work on just their parts. In the case of HTML and style, I would tell the designer I was using <p>, <h1>, and <h2> for different levels of text, and then the designer could work on the look of these styles. Later, when we start writing larger JavaScript programs, we will discover a way of separating the program code from the HTML, which allows another level of separation.

Creating style classes

If we are making a simple web application, we might be able to express all our formatting requirements using the paragraph and heading styles. However, a more complex application would need to contain other styles. For example, we might want to have a different format for displaying an address. It might need to be red, in a monospaced font, and aligned to the right-hand margin. We can add a new style class called address to the style sheet for a document:

Click here to view code image

.address {
    color: red;
    font-family: 'Courier New', Courier, monospace;
    text-align:  right;
}

Notice that this looks like the way that we modified the styling of <p>, except that the address class has a leading dot (.) to indicate that this is a newly created style class: .address. We can then specify that this class provides the style of a paragraph:

Click here to view code image

<p class="address"> This is an address paragraph.</p>

The class attribute of an element specifies a CSS (Cascading Style Sheet) style class that is to be used to style the element. This means that the text in the paragraph above would be drawn in a red and monospaced font at the right-hand side of the page. You can see this in action in the Ch03 HTML/ Ch03-14 Address Style folder. You can create as many style classes as you need. If you were working with a designer, you would both agree on the style names to be used for the various elements, and then you could generate HTML files elements tagged with the classes that should be used to format them.

MAKE SOMETHING HAPPEN

Exploring style sheets

We can use the Developer menu in the browser to take a look at how the style sheets work. Find the Ch03 HTML/Ch03-14 Address Style Class folder and open the index.html file with your browser. This shows you the address paragraph formatted with a red monospaced font. Press F12 to open the Developer menu. Then select the Sources tab in the dialog box at the top of the Developer menu.

You can now see the index.html and style.css files. If you click them, you can view their contents. When we start making more complex web pages, you’ll find this view very useful. You can use it to view the sources of any web page you visit, but don’t get discouraged by how complicated they seem.

Formatting parts of a document using <div> and <span>

We can add a class attribute to any element of text that we want to format, but sometimes it is useful to apply a style class to multiple items. In the case of the address style above, we would like to mark all the paragraphs in the address that we are displaying. We could mark each paragraph individually, but it would be nice if we could mark them all at once. The <div> and <span> elements make this possible. They are used to create regions to which classes can be assigned.

Click here to view code image

<!DOCTYPE html>
<html lang="en">

<head>
    <title>Ch03-14 Address Style</title>
    <link rel="stylesheet" href="styles.css">
</head>

<body>
    <div class="address">
        <p>Rob Miles</p>
        <p>18 Pussycat Mews</p>
        <p>London</p>
        <p>NE14 10S</p>
    </div>
</body>

</html>

The HTML above would format all the paragraphs of the address using the address class because they are enclosed in a division. The div element specifies a division in the document. Each div element marks the start and end of a paragraph of text. This means that we can’t use a div element to set the style of some words in a paragraph. If we want to just format part of a paragraph using a particular style, we can use the span element.

Click here to view code image

<p>An HTML document can use the
<span class="codeInText">style</span>
attribute to add style to any element in a document.</p>

In the example above, I want the word style to stand out from the text because it is an HTML element name. I’ve created a class called codeInText and used it to apply a style to the word style in the sentence. I can’t use div in this situation because this would break the sentence over several lines. The Ch03 HTML/ Ch03-16 Code Style with span example shows how it works. You can put span and div elements inside each other, but it doesn’t make much sense to put a div inside a span because this would cause paragraph breaks in your line of text. You must, of course, make sure that any “nesting” is properly formatted. Take a look at the Programmer’s Point “Don’t abuse the browser” in Chapter 2 for more details on this issue.

Cascading styles

You might be wondering why they are called cascading style sheets. The name refers to the way styles “cascade” down from one element to all the elements it encloses. Consider the following HTML:

Click here to view code image

<!DOCTYPE html>
<html lang="en">
<head>
<title>Ch03-17 Cascading Styles</title>
</head>
<body style="color: blue;">
<p>This is an ordinary paragraph.</p>
<p style="color:red">This is a red paragraph.</p>
<p style="background: yellow;">This has a yellow background.</p>
</body>
</html>

The document contains three style elements. The first is applied to the body of the document. The next two are applied to elements inside the body of the text. The body element has been styled with the color blue. The body element encloses the two paragraph elements, so this setting cascades down onto these paragraphs, as shown in Figure 3-11.

Figure 3-11 Cascading styles in action

The “ordinary” paragraph has blue text because of the style applied to the enclosing body element. The red paragraph is red because the color setting in the style for the paragraph overrides the cascading style. However, the text with a yellow background has blue text because the style on this paragraph does not modify the color in the enclosing one; instead, it modifies the color of the text background. The rule is that style settings are “inherited” from enclosing elements unless they are “overridden” in them.

PROGRAMMER’S POINT

Managing styles is all about design

As you go through this book, I want to you learn that a lot of solution development is about making your life easier. For example, you might have a problem if you showed your customer the solution you had built and they told you they want shocking-pink text on an orange background (it has been known). If you’d applied the text style to each HTML element, this would mean you would have to work through the entire document and make the requested changes. If you’ve used style sheets properly, you should be able to change just one file to make a change like this.

A huge amount of programming is about organization and planning. This chapter has introduced some excellent tools that you can use to create and manage the appearance of an HTML page.

Color highlighting using selectors

Earlier in this chapter, in “Make Something Happen: Color highlighting on mouse rollover,” we used the onmouseover event to trigger a JavaScript function to change the color of text in a paragraph. At the time, I said that there is a much easier way to make text appear as highlighted when the user rolls their mouse over it.

.rollover {
    color:black;
}

.rollover:hover {
    color:red;
}

The style sheet above creates a style called rollover. There are two definitions for the style. The first definition just sets the color as black. The second definition of rollover has an additional selector: hover. A selector indicates the circumstance in which this variant of the style should be used. The hover selector specifies that this style is to be used when the mouse is hovering over an element with the class set to rollover. This style sets the color to red. If you view this page in the Ch03 CSS\Ch03-18 Rollover with CSS folder, you will see how it works.

There is a lot more you can do with selectors. You can use them to set styles for unvisited links, or selected items, and you can even use them to set the first letter of a paragraph. You can find a full reference at the following Mozilla page. You will have to work hard to understand all of it (I did), but it is powerful stuff: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors.

What you have learned

This chapter has given you a good understanding of what style is and how to manage it. Here are the major points we covered in this chapter:

The definition of an element in an HTML page can include a style attribute that describes how the element should be displayed, such as to make the text in a paragraph red.

The definition of an element can also include event attributes that execute a piece of JavaScript code when a particular event occurs, such as the onmouseover event triggering code when the user moves the mouse pointer over the element.

The style information for a text element can include the font to be used to draw the text. Fonts are specified as families, which include all the variants of the text to be displayed (such as italic and bold). It is conventional to provide a number of different font-family values when specifying font options because systems use different names for popular font designs.

The size of elements in an HTML document can be specified in multiple ways. If the intention is to change the size of text relative to other text, the size should be expressed in em units, where an em value of 1 is “normal-sized” text.

Text can be aligned across an HTML page using the text-align attribute.

The setInterval function can be used to call a JavaScript function at regular intervals. We used this to create a ticking clock.

The style of an element can include definitions for margin, padding, and border items. The margin is the outer margin around the element. The border can be drawn in a variety of styles and colors, and the border has a set thickness. The padding value sets how far the item is placed away from the border.

When specifying the dimensions of borders and margins around HTML elements, the px unit can be used. A value expressed in px units represents a number of pixels and equates to the size of a pixel in an image. Using px units means that you can get absolute control over the layout of items at the expense of portability. (For example, the pages might look too large or too small on some devices.)

A style sheet contains style settings that can be assigned to elements in an HTML document. Style settings can modify styles such as <p>, <h1>, and <h2>, or they can create completely new styles that can be assigned to elements using the class attribute.

A style sheet can be held in a file that is separate from an HTML page. The page contains a link element in the page heading that identifies the style sheet file to be used. This allows complete separation between the content and the styling of a page.

Styles are applied to elements in a way that cascades down from enclosing elements. For example, if the body of a document is styled with red text, that setting will cascade down into any elements in the document. However, a color style attribute in a paragraph inside the document will override this cascading setting.

The div and span elements act as containers around other elements. Style attributes applied to the div and span elements cascade down into all the elements contained in them. When a div element is rendered, the browser will insert line breaks at the start and the end of the div. This does not happen with a span element, making the span element useful for applying styles to words in sentences.

To reinforce your understanding of this chapter, you might want to consider the following “profound questions” about styles and style sheets.

Can I add a style attribute to any element?

Yes. It might not be sensible to set the font of the script element in an HTML file, but it will not cause an error if you do.

What happens if I add an irrelevant style to an item?

Nothing. If you want to set a font for the <script> part of your HTML file, you can do that, and you will not get any errors, but it would not be a sensible thing to do.

What happens if I set conflicting style settings?

The most “recently” applied style will be the one that is enforced. In other words, if the text color of the body of the document is set to black, but the text color of the paragraph in the body is set to red, the text will be red. This is how “cascading” works.

Is a CSS file a program?

No. The JavaScript programs that we have written set out a sequence of actions to be performed. A CSS file contains a number of style settings items that are applied to HTML elements that are assigned to them.

Is redText a good name for a CSS style class?

I don’t think so. If your customer decides that they really want to change to blue text for that style, you can’t easily change the name of the class. The name of a class should reflect what you want a style to achieve. For example, you could have a class called displayName, which is used to display names, and you could have another class called displayAddress for addresses. If a style is being displayed as red, that’s something that would be reflected in the settings for that style class, not in the name of the class itself.

Can I store CSS files on a different server from the HTML file that contains the web page?

Yes, you can. The link element that gets the CSS file contains a URL that can refer to a file on a distant machine.

When should I use div, and when should I use span?

Div is used if you want to control the style of some elements that make up a division in your page. By division, I mean something like an entire address, an order, or a report. The division will be separated from the rest of the page by line breaks. Span is used when you want to style a small portion of a paragraph. For example, you might use span to highlight the word code in this sentence. In this case, you don’t want any line breaks in the text.

What is the difference between id and class?

An element on a web page can have a setting for an id value and a class value. The id value is unique for that element in the HTML document. JavaScript code that works with the document can locate an element by its id. The class value specifies the style to be applied to this element. A large number of elements in a document can have the same class value. This would make changing the style of these elements very easy because the designer would just have to change the definition of the class in the style sheet, and it would be applied to all the elements.

What is the difference between the em and px units?

This is confusing. Not least because em also means “emphasized” when applied to text. An em value of 1 refers to the size of a “normal” character in the current font. So, I can specify a size in em values so that I can make my text larger or smaller relative to the rest of the text. I don’t want to use an absolute value for my text size because, as we have seen, different fonts have different “standard” text sizes, and I don’t want everything to become too large or too small if the font changes. So em is very useful if you want to express that some things are bigger than others, but you don’t want tie things to specific sizes.

A px value refers to a number of “pixels” on the screen. Modern high-resolution screens have pixels that are so small that this might not be an accurate mapping, but the idea is that px values give you the ability to place things more precisely, particularly in relation to images, which are also sized using pixel dimensions. So em is used if you want to lay elements out very precisely in relation to each other.

Is this all there is to CSS?

Absolutely not. We have barely scratched the surface in this chapter. You can perform animation, fade images in and out, and do all manner of other things too. The great thing is that the interactive help from tools like Visual Studio Code and the wonderful Developer Console in the browser allow you to experiment with styles to find out more. It is certainly worth doing this. As we have seen when we looked at the rollover style selector, we can replace JavaScript code with style sheet behavior. One of the rules of HTML development is that you should always check to see if a style sheet could be used to get the effect that you want before you write any JavaScript code. Just because you could write a program to get a particular effect doesn’t mean that you should.

Part 2
Coding with JavaScript

In this part, we start writing JavaScript applications. We’ll discover how to create complete programs that run inside the browser. We’ll gain fundamental programming knowledge of data storage and processing in software. Then we’ll move on to a discussion of how to structure solutions and break a large program into smaller components. Finally, we’ll take a look at software objects and how they can be used to create custom data storage types that map program storage to real-world data.

4
Working with data

What you will learn

In this chapter, you’ll build more JavaScript programs. You’ll discover that a computer is fundamentally a data processor and that a program tells the computer what to do with the data. You’ll see how programs store data using variables, and you’ll learn how JavaScript manages diverse kinds of data that can be stored by a program. You’ll also learn how JavaScript manages the visibility of variables within a program. By the end of this chapter, you’ll be able to create useful programs.

Computers as data processors

Data and information

Variables in programs

Working with variables

Random numbers

Working with text

Converting strings into numbers

Making applications

Fix the pizza program

Global and local variables

Make some party games

What you have learned

Computers as data processors

Humans are a race of toolmakers. We invent things to make our lives easier, and we’ve been doing it for thousands of years. We started with mechanical devices, such as the plow, which made farming more efficient. In the last century, we’ve moved into electronic devices and, more recently, into computers.

As computers have become smaller and cheaper, they have found their way into things around us. Many devices (for example, the smartphone) are possible only because we can put a computer inside to make them work. However, we need to remember what the computer does; it automates operations that formerly required brain power. There’s nothing particularly clever about a computer; it simply follows the instructions that it’s been given.

A computer works on data in the same way that a sausage machine works on meat: Something is put in one end, some processing is performed, and something comes out the other end. A program tells a computer what to do in the same way that a coach gives instructions to a football or soccer team before a play. The coach might say something like, “If they attack on the left, I want Jerry and Chris to run back, but if they kick the ball down the field, I want Jerry to chase the ball.” Then, when the game unfolds, the team will respond to events in a way that should let them outplay their opponents.

However, there is one important distinction between a computer program and the way a team might behave in a football game. A football player would know when he or she is given some senseless instructions. If the coach said, “If they attack on the left, I want Jerry to sing the first verse of the national anthem and then run as fast as he can toward the exit,” the player would raise an objection.

Unfortunately, a program is unaware of the sensibility of the data it is processing, in the same way that a sausage machine is unaware of what meat is. Put a bicycle into a sausage machine, and the machine will try to make sausages out of it. Put meaningless data into a computer, and it will do meaningless things with it. As far as computers are concerned, data is just a pattern of signals coming in that must be manipulated in some way to produce another pattern of signals. A computer program is the sequence of instructions that tell a computer what to do with the input data and what form the output data should have.

Examples of typical data-processing applications include the following (as shown in Figure 4-1):

Smartphone—A microcomputer in your phone takes signals from a radio and converts them into sound. At the same time, it takes signals from a microphone and makes them into patterns of bits that will be sent out from the radio.

Car—A microcomputer in the engine takes information from sensors telling it the current engine speed, road speed, oxygen content of the air, accelerator setting, and so on. The microcomputer produces voltages that control the carburetor settings, the timing of the spark plugs, and other things to optimize engine performance.

Game console—A computer takes instructions from the controllers and uses them to manage the artificial world that it is creating for the gamer.

Figure 4-1 Computers in devices

Item 1, Mobile phone; input, Radio Signals Touchpad; and output, Sound Pictures. Item 2, Car; Input, Temperature Pressures Throttle; and Output, Fuel Injector Ignition timings. Item 3, Consol; Input, Gamepad; Outputs, Gameplay.

Most reasonably complex devices created today contain data-processing components to optimize their performance, and some exist only because we can build-in such capabilities. The growth of the Internet of Things (IoT) is introducing computers into a huge range of areas. It’s important to think of data processing as much more than working out the company payroll—calculating numbers and printing out results (the traditional uses of computers). As software engineers, we will inevitably spend a great deal of our time fitting data-processing components into other devices to drive them. These embedded systems mean many people will be using computers, even if they’re not aware of it!

PROGRAMMER’S POINT

Software might be a matter of life and death

Remember that seemingly innocuous programs can have life-threatening capabilities. For example, a doctor may use a spreadsheet you have written to calculate doses of drugs for patients. In this case, a defect in the program could result in physical harm. (I don’t think doctors do this—but you never know.) For a deeply scary description of how poor software design can cause injury and even death, search for Therac-25 on the web.

Programs as data processors

Figure 4-2 shows what every computer does. Data goes into the computer, which does something with it, and then data comes out of the computer. What form the data takes and what the output means are entirely up to us, as is what the program does.

Figure 4-2 A computer as a data processor

Another way to think of a program is like a recipe, which is illustrated in Figure 4-3.

Figure 4-3 Recipes and programs

In this example, the cook plays the role of the computer, and the recipe is the program that controls what the cook does with the ingredients. A recipe can work with many different ingredients, and a program can work with many different inputs, too. For example, a program might take your age and the name of a movie you want to see and provide an output that determines whether you can go see that movie based on its audience rating.

JavaScript as a data processor

Figure 4-4 shows the workings of one of the early example programs, Ch02-08 Paragraph Update, from a data processing perspective. The input to the program is an input box on the HTML page, and the output from the program is the text in a paragraph in the HTML page. In this case, the JavaScript program code is in the function doUpdateParagraph, which runs when the user presses a button on the page. This function doesn’t perform any processing on the data input; it simply transfers text from the input element to the output element.

Figure 4-4 JavaScript as a data processor

The screenshot of a html page is displayed. Here, the input passes to the java script function and delivers the output. A JavaScript code displayed the function 'doUpdate paragraph ()' to convert the data in the input field to a text in a paragraph.

This is a program structure that we will be using a lot in the next few chapters. We can change what a program does by changing the instructions in the functions that run inside the web page. Statements in a function will act on data and generate new values by evaluating expressions.

Process data with expressions

An expression can be as simple as a single value (for example 2 or Rob Miles), or it can contain operators and operands. Figure 4-5 shows a simple expression with two operands and one operator. Things that do the actual work are called operators. In the case of 2+2, there are two operands (the two values of 2) and one operator (+). When you feed an expression into the JavaScript command prompt, it identifies the operators and operands and then works out the answer.

Figure 4-5 Expression

In Chapter 1 in “Our first brush with JavaScript,” we entered some expressions and saw the results. Now let’s enter some more.

CODE ANALYSIS

Evaluate expressions with JavaScript

The function shown previously in Figure 4-4 doesn’t process any data; instead, it simply transfers the text from the input to the output. Data processing in JavaScript is performed by the evaluation of expressions. An expression can be as simple as a single value (which is called a literal because it is taken exactly as it is). Alternatively, an expression could perform a complicated calculation. Let’s do some expression evaluation to find out more.

Question: Can JavaScript work out 2+2?

Answer: I hope so. Go to the example folder Ch04 Working with data\Ch04-01 Empty Page. Press F12 to open the Developer View of the web page and select the Console tab. Type the expression 2+2 and press Enter.

The screenshot shows the developer's view of the web page. It consists of various tabs such as elements, console, source, network, and performance. Here the console tab is selected. The expression 2 plus 2 is displayed in the first row, and the result 4 is displayed in the second row.

The JavaScript console always attempts to evaluate any expression you give it and then return the result. In this case, it has worked out that 2+2 equals 4. We can do some more experiments using the console to investigate expressions. From now on, rather than showing you screenshots of the browser, I’ll just show the output that you’ll see in the console. In other words, the previous expression would look like this.

> 2+2
<- 4

The typed text is shown in black, the output from JavaScript is shown in blue, and the command prompts are shown in brown.

Question: What do you think would happen if you tried to evaluate 2+3*4?

Answer: The * (asterisk) operator means multiply. JavaScript uses the asterisk in place of the × (multiplication symbol) used in math. In math, we always perform higher-priority operations like multiply and divide before addition, so I’d expect the expression above to display the value 14. The calculation 3*4 would be worked out first, giving an answer of 12, and this would be added to the value 2. If you try this in the console, you should see what you would expect:

> 2+3*4
<- 14

Question: What do you think would happen if you tried to evaluate (2+3)*4?

Answer: The parentheses enclose calculations that should be worked out first, so in the above expression, I’d expect to see the value 5 calculated (2+3) and then this value to be multiplied by 4, giving a result of 20.

> (2+3)*4
<- 20

Question: What do you think would happen if you tried to evaluate (2+3*4?

Answer: This one is quite interesting. You should try it with the console. What happens is that JavaScript says to itself, “The expression I’m trying to work out is incomplete. I need a closing parenthesis.” So, the console waits for more input from you. If you type the closing parenthesis and complete the expression, the value is calculated and the result is displayed. You can even add more sums on the second line if you want.

> (2+3*4
       )
<- 14

Question: What do you think would happen if you tried to evaluate )2+3*4?

Answer: If JavaScript sees a closing parenthesis before it sees an opening one, it instantly knows that something is wrong and displays an error.

Click here to view code image

> )2+3*4
(x) Uncaught SyntaxError: unexpected token ')'

Note that the command shell is trying to help you work out where the error is by identifying the incorrect character.

Scripting languages

We can use the console for having conversations like this because JavaScript is a “scripting” programming language (the clue is in the name). You can think of the console as a kind of “robot actor” who will perform whatever JavaScript statements you give it. In other words, you tell the console what you want your program to do using the JavaScript language. If the instructions don’t make sense to the “robot actor,” it tells us it can’t understand them (usually with red text). The process of taking a program and then acting on the instructions in it is called interpreting the program. Actors earn a living interpreting the words of a play; computers solve problems for us by interpreting program instructions.

PROGRAMMER’S POINT

Not all programming languages run like JavaScript

Not all programming languages are “scripting” languages, which are interpreted in the same way as JavaScript. Sometimes, program instructions are converted into the very low-level instructions that the hardware of your computer understands. This process is called compilation, and the program that performs this conversion is called a compiler. The compiled instructions can then be loaded into the computer to be executed. This technique produces programs that can run very fast because when the compiled low-level instructions are performed, the computer doesn’t have to figure out what the instructions mean; they can just be obeyed.

You might think this means that JavaScript is a “slow” computer language because each time a JavaScript program runs, the “robot actor” must work out the meaning of each command before performing it. However, this is not really a problem because modern computers run very, very fast, and JavaScript uses some clever trickery to compile your program as it runs.

Data and information

Now that we understand computers as machines that process data, and we understand that programs tell computers what to do with the data, let’s delve a little bit deeper into the nature of data and information. People use the words data and information interchangeably, but it’s important to make a distinction between the two, because the way that computers and humans consider data is completely different. Look at Figure 4-6, which shows the difference.

Figure 4-6 Data and information

The screenshot shows the difference between the computer's and human's view of data. The left pane of the screen shows numerical values which the computer understands. The right pane of the screen shows a processed document, which the humans can understand.

The two items in Figure 4-6 contain the same data, except that the image on the left more closely resembles how the document would be stored in a computer. The computer uses a numeric value to represent each letter and space in the text. If you work through the values, you can figure out each value, beginning with the value 87, which represents an uppercase W (in the “When” that begins the first regular paragraph in the document on the right).

Because of the way computers hold data, yet another layer lies beneath the mapping of numbers to letters. Each number is held by the computer as a unique pattern of on and off signals, or 1s and 0s. In the realm of computing, each 1 or 0 is known as a bit. (For a wonderful explanation of how computers operate at this level and of how these workings form the basis for all coding, see Charles Petzold’s Code: The Hidden Language of Computer Hardware and Software.) The value 87, which we know means “uppercase W,” is held as the following way:

1010111

This is the binary representation of the value. I don’t have the space to go into precisely how this works (and Charles Petzold already did this!), but you can think of this bit pattern as meaning “87 is made up of a 1 plus a 2 plus a 4 plus a 16 plus a 64.”

Each of the bits in the pattern tells the computer hardware whether a particular power of 2 is present. Don’t worry too much if you don’t fully understand this but do remember that as far as the computer is concerned, data is a collection of 1s and 0s that computers store and manipulate. That’s data.

Information, on the other hand, is the interpretation of the data by people to mean something. Strictly speaking, computers process data and humans work on information.

For example, the computer could hold the following bit pattern somewhere in memory:

Click here to view code image

11111111 11111111 11111111 00000000

You could regard this as meaning, “You are $256 overdrawn at the bank” or “You are 256 feet below the surface of the ground” or “Eight of the thirty-two light switches are off.” The transition from data to information is usually made when a human reads the output.

I am being so pedantic because it is vital to remember that a computer does not “know” what the data it is processing means. As far as the computer is concerned, data is just patterns of bits; it is the user who gives meaning to these patterns. Remember this when you get a bank statement that says you have $8,388,608 in your account when you really have only $83!

Data processing in JavaScript

We now know that JavaScript is a data processor. A script containing JavaScript statements is interpreted by the browser, which then produces some output. We also know that within the computer running a JavaScript program, data values are represented by patterns of bits (representing ons and offs). Now we need to discover how variables let our programs store and manipulate the data being processed.

Variables in programs

We have already used quite a few variables in our JavaScript programs. Variables are how programs remember things. You can think of a variable as a storage location you can refer to by name. What you store in the location and the name you give the location are up to you. You can create a variable in a JavaScript program by thinking of a name for the variable and then putting a value in the variable. Perhaps you know someone with a pressing need to add up some numbers. In this case, the first statement in your program might look like this:

The screenshot shows an assigned variable that reads "Var Total;" Here, var tells JavaScript that the program is creating a variable, and total is the name of the variable.

If we want to add up a bunch of numbers, we will need something to store the total value. This statement creates a variable with the name total. The program will set the initial value of total to 0 and then add each number to it. To set the initial value of the total variable, we use an assignment statement:

total = 0;

The = in the statement tells JavaScript that the program is performing an assignment. The variable name on the left-hand side of the equals symbol specifies the destination of the assignment (meaning the place to put the result). The expression on the right-hand side provides the result to store in the variable. When JavaScript sees a variable name in an expression, it fetches the value out of the variable and uses that value. This means the following statement should make perfect sense to you:

total = total + 1;

The item on the right-hand side of the statement is an expression, which will generate a result. JavaScript gets the value of total and adds 1 to it. It then puts this result into the variable total. In other words, the effect of the statement above is to increase the value in total by 1.

MAKE SOMETHING HAPPEN

Working with variables

Let’s have a look at variables in JavaScript by using the Developer Tools. Start your browser and navigate to the page in the Ch04 Working with data\Ch04-01 Empty Page folder. Open up the Developer View by pressing F12. You can begin by creating a total variable.

> var total;

When you press Enter, JavaScript will create the variable. However, it gives a rather strange response:

> var total;
<- undefined

This response occurs because every time the console performs a statement, it then displays the value generated by that statement. Creating a new variable doesn’t create a value, so the console displays the value as undefined. You can see this in action if you enter a statement that assigns a value to total. Enter the statement below and look at the result:

> total = 0;
<- 0

In JavaScript, the result of an assignment is the value that is assigned, so this statement will generate the value 0. Let’s try performing the addition we saw in the text:

> total = total + 1;
<- 1

This statement works out the value of total + 1 (which will be 0 + 1) and then assigns this to the total variable. The effect of this is that total now contains the value 1. Perform the statement again.

> total = total + 1;
<- 2

Each time we perform the addition statement, the value in total gets larger by 1. This expression might appear confusing. If you’ve worked with mathematical equations, you’ll remember that the equals character (=) means that one value is equal to another. From a mathematical point of view, the statement generated above is obviously wrong because the total cannot equal the total plus 1. However, it’s important to remember that in JavaScript, the equals operator means “assign.” So, the expression total+1 is evaluated on the right side and then is assigned to the variable on the left side. In JavaScript, it is perfectly okay to create a variable and assign it a value immediately:

> var total=0;

If you do this, you will notice that the result displayed by the console is undefined because, as we saw at the start of this section, a statement that creates a variable does not return a value. If you haven’t set a value into a variable, JavaScript marks that variable as holding the value undefined. Enter this statement to create a new variable called test.

> var emptyTest;

Now you can investigate the value that the newly created variable emptyTest holds. If you just enter the emptyTest variable, the console will hold the value stored in the variable emptyTest:

> emptyTest
<- undefined

Note that this does not mean that the variable emptyTest does not exist. Instead, it means that the variable emptyTest does not hold a value. The contents of emptyTest are undefined. We can pass the undefined value around as we would any other:

> emptyCopy=emptyTest;
<- undefined

Now I have a variable called emptyCopy that holds a copy of emptyTest. Both of these variables hold the undefined value. If I use an undefined value in a calculation, I won’t get an error, but I will get a result that is not a number:

> emptySum=emptyTest + 1;
<- NaN

This kind of calculation will not cause a problem with your program, except that it will produce silly results. JavaScript makes a distinction between things that are not defined and things that do not exist. If you try to view the value in a variable that does not exist, something different happens. Enter the name notDefined and press Enter:

Click here to view code image

>notDefined
Uncaught ReferenceError: notDefined is not defined at <anonymous>:1:1

The variable notDefined does not exist, so JavaScript gives us an error.

JavaScript identifiers

Names of things in JavaScript are called identifiers. We used the identifier total for the first variable that we created. When you write a program, you must come up with identifiers for the variables in that program. JavaScript has rules about the way you can form identifiers:

An identifier must start with a letter, the dollar character ($), or the underscore character (_) and can contain letters, numerals (digits), or the underscore character.

The name total is a perfectly legal identifier, as is xyz. However, the identifier 2_be_or_not_2_be would be rejected with an error because it starts with a digit. Also, JavaScript views uppercase and lowercase letters differently; for example, FRED is regarded by JavaScript as different from fred.

PROGRAMMER’S POINT

Create meaningful identifiers

I find it terribly surprising that some programmers use identifiers such as X21 or silly or hello_mum. I don’t. I work very hard to make my programs as easy to read as possible. So, I’ll use ones such as length or, perhaps even better, windowLengthInInches. My window length identifier uses a format where the first letter of each word inside the identifier is a capital letter. This is called camel case because the capital letters in the name stick up like humps on the back of a camel. Another convention uses the underscore character to split up the words in an identifier: window_length_in_inches. I reckon either of these is okay, although camel case is more common in JavaScript. I don’t care which one you use, but I do care that you use it consistently throughout your program.

I don’t care which method you choose to make up your identifiers; I only care that you strive to create identifiers with meaning. If the identifier applies to a particular thing, then identify that thing. And if that thing has particular units of measurement, then then add those, too. For example, if I were storing the age of a customer, I’d create a variable called customerAgeInYears.

JavaScript allows identifiers of any length, and longer identifiers don’t slow down a program. However, very long names can be a bit hard for humans to read, so you should try to keep them down to the lengths shown in the examples.

CODE ANALYSIS

Code errors and testing

By now, you should be getting used to the idea that if you give a JavaScript program the wrong instructions, the wrong thing will happen. However, consider the JavaScript below, which is supposed to add 1 to the value in the variable with the name total:

Total = total + 1

Question: There is an error in the statement above, which is supposed to add 1 to the variable total. What is the error?

Answer: Earlier in this chapter, we used a statement that looks like this to add 1 to the value in a variable called total. It looks like we are doing the same thing here, but that’s not the case. There is a crucial difference between this statement and the one we saw earlier. This statement assigns the result of the calculation to a newly created variable called Total. The error can happen because although we have used the word var to tell JavaScript that we are declaring a variable, this is not something that JavaScript insists on. If you assign something to a variable that JavaScript has not seen before, JavaScript will just create a new variable with the specified name.

The statement would not generate any complaints from JavaScript when it runs, but it would also not update the value of total correctly. Instead it would create a new variable called Total. This is a logic error. The statement is completely legal as far as JavaScript is concerned, but it will do the wrong thing when it runs.

I mentioned at the start of this book that JavaScript has some features that make me want to tear my hair out. This is one of them because it means that your punishment for a simple typing mistake is not an error or warning message. Instead you get a program that runs but doesn’t work properly.

Question: How do we prevent logic errors?

Answer: The only way to attack logic errors is to test. We need to run a program with some known values (values for which we know the total) and then verify that the answers agree with the test total. If the answers make sense, we can start to build confidence in our code. However, even if a program passes all the tests, it could still be faulty because there might be a fault that is not picked up by those tests.

Tests don’t prove that a program is good; tests simply prove that a program is not as bad as it would be if it had failed the tests.

Tests work best if they are added at the time the program is created. We’ll talk about testing strategies every time we make a new program.

total = Total + 1

Question: The statement above also contains a misspelling of a variable named total. However, this time the name on the right-hand side of the equals is misspelled. What will happen when this program runs?

Answer: JavaScript will refuse to run this statement. It will tell you that you are using a variable with the name Total, which it hasn’t seen yet. Sometimes, typing mistakes will be detected before your program runs, but other times, they might not.

You might be thinking that you’ve been set up to fail because I’ve suggested that you use long, meaningful names, and typing those long, meaningful names creates more opportunities for mistakes. For now, one way around this problem is to use the text copy feature of your editor to copy names from one part of the program to another.

Performing calculations

We know that JavaScript expressions are made up of operators and operands. The operators identify actions to be performed, and the operands are worked on by the operators. Now we can add a bit more detail to this explanation. Expressions can be as simple as a single value or as complex as a large calculation. Here are a few examples of numeric expressions:

2 + 3 * 4
-1 + 3
(2 + 3) * 4

These expressions are evaluated by JavaScript by working from left to right, just as you would read them yourself. Again, just as in traditional math, multiplication and division are performed first, followed by addition and subtraction. JavaScript achieves this order by giving each operator a priority. When JavaScript works out an expression, it finds all the operators with the highest priority and applies them first. It then looks for the operators next in priority, and so on, until the result is obtained. The order of evaluation means that the expression 2 + 3 * 4 will calculate to 14, not 20.

If you want to force the order in which an expression evaluates, you can put parentheses around the elements of the expression you want to evaluate first, as in the final example above. You can also put parentheses inside parentheses if you want—provided you make sure that you have as many opening parentheses as closing ones. Being a simple soul, I tend to make things clear by putting parentheses around everything.

It is probably not worth getting too worked up about expression evaluation. Generally speaking, things tend to be evaluated how you would expect. Here is a list of some other operators, with descriptions of what they do and their precedence (priority). The operators are listed with the highest priority first.

Operator

How it’s used

-

Unary minus. This is the minus that JavaScript finds in negative numbers.

*

Multiplication. Note the use of the * rather than the more mathematically correct but confusing x.

/

Division. Because of the difficulty of drawing one number above another during editing, we use this character instead.

+

Addition.

-

Subtraction. Note that we use the same character as for unary minus.

This is not a complete list of the operators available, but it will do for now. Because these operators work on numbers, they are often called numeric operators. However, one of them, the + operator, can be applied between strings, as you’ve already seen.

CODE ANALYSIS

Work out the results

Question: See if you can work out the values of a, b, and c when the following statements have been evaluated:

var a = 1;
var b = 2;
var c = a + b;

c = c * (a + b);
b = a + b + c;

Answer: a=1, b=12, c=9. The best way to work this out is to behave like a computer would and work through each statement in turn. When I do this, I write down the variable values on a piece of paper and then update each as I go along. Doing this means that you can predict what a program will do without having to run it.

Whole numbers and real numbers

We know that JavaScript is aware of two fundamental kinds of data—text data and numeric data. Now we need to delve a little deeper into how numeric data works. There are two kinds of numeric data—whole numbers and real numbers. Whole numbers have no fractional part. Up until now, every program that we have written has made use of whole numbers. A computer stores the value of a whole number exactly as entered. Real numbers, on the other hand, have a fractional element that can’t always be held accurately in a computer.

As a programmer, you need to choose which kind of number you want to use to store each value.

CODE ANALYSIS

Whole numbers versus real numbers

You can learn about the difference between whole numbers and real numbers by looking at a few situations in which they might be used.

Question: I’m building a device that can count the number of hairs on your head. Should I store this value as a whole number or as a real number?

Answer: This should be a whole number because there is no such thing as half a hair.

Question: I want to use my hair-counting machine on 100 people and determine the average number of hairs on all their heads. Should I store this value as a whole number or as a real number?

Answer: When we work out the result, we’ll find that the average includes a fractional part, which means that we should use a real number to store it.

Question: I want to keep track of the price of a product in my program. Should I use whole numbers or real numbers?

Answer: This is very tricky. You might think that the price should be stored as a real number—for example, $1.50 (one and a half dollars). However, you could also store the price as the whole number, 150 cents. The type of number you use in a situation like this depends on how that number is used. If you’re just keeping track of the total amount of money you take in while selling your product, you can use a whole number to hold the price and the total. However, if you are also lending money to people to buy your product and you want to calculate the interest to charge them, you would need a fractional component to hold the number more precisely.

PROGRAMMER’S POINT

The way you store a variable depends on what you want to do with it

It seems obvious that you would use a whole number to count the number of hairs on your head. However, one could argue that we could also use a whole number to represent the average number of hairs on 100 people’s heads. This is because the calculated average would be in the thousands. Fractions of a hair would not add much useful information, so we could drop any fractional parts and round to the nearest whole number. When you consider how you are going to represent data in a program, you must take into account how it will be used.

Real numbers and floating-point numbers

Real number types have a fractional part, which is the part of the number after the decimal point. Real numbers are not always stored exactly as they are entered into JavaScript programs. Numbers are mapped to computer memory in a way that stores a value that is as close as possible to the original. The stored data is often called a floating-point representation. You can increase the accuracy of the storage process by using larger amounts of computer memory, but you are never able to hold all real values precisely.

This is not a problem, however. Values such as pi can never be held exactly because they “go on forever.” (I’ve got a book that contains the value of pi to 1 million decimal places, but I still can’t say that this is the exact value of pi. All I can say is that the value in the book is many more times more accurate than anyone will ever need.)

When considering how numbers are stored, we need to think about range and precision. Precision sets out how precisely a number is stored. A particular floating-point variable could store the value 123456789.0 or 0.123456789, but it can’t store 123456789.123456789 because it does not have enough precision to hold 18 digits. The range of floating-point storage determines how far you can “slide” the decimal point around to store very large or very small numbers. For example, we could store the value 123,456,700, or we can store 0.0001234567. For a floating-point number in JavaScript, we have 15 to 16 digits of precision, and we can slide the decimal point 308 places to the right (to store huge numbers) or 324 places to the left (to store tiny numbers).

The mapping of real numbers to a floating-point representation does bring some challenges when using computers. It turns out that the value 0.1 (a tenth) may not be held accurately by a computer. The value stored to represent 0.1 will be very close to that value, but not the same. This has implications for the way we write programs.

CODE ANALYSIS

Floating-point variables and errors

We can find out more about how floating-point values work by doing some experiments using the JavaScript Developer View in the browser. If we just type numeric expressions, we can view the results that JavaScript calculates.

Question: What happens if we try to store a value that can’t be held accurately as a floating-point value?

Answer: We know that the value 0.1 can’t be held accurately in a computer, so let’s enter that value into the Developer View and see what comes back. Go to the console in browser and enter the following:

>  0.1
<- 0.1

At this point, you might think that I’ve been lying to you because I said that the value 0.1 can’t be held accurately, and now this example shows JavaScript returning the value 0.1. However, I’m not lying to you—JavaScript is. The JavaScript print routine “rounds” values when it prints them. In other words, it says that if the number to be printed is 0.10000000000000000551115 or thereabouts (which it is), then it will just print 0.1.

Question: Does this “rounding” really happen?

Answer: At the moment, you’ve just got my word for it that values are rounded when printed and that errors are being hidden from us as a result. However, if we perform a simple calculation, we can introduce an error that is large enough to escape being rounded. Enter the following calculation into the JavaScript Shell and note what comes back.

>  0.1+0.2
<- 0.30000000000000004

The result of adding 0.1 to 0.2 should be 0.3, but because the values are held as binary floating-point values, the result of the calculation contains an error large enough to escape being rounded.

However, this lack of accuracy is not a problem in programming because we don’t usually have incoming data that is particularly precise anyway. For example, if I refine my hair counting device to measure hair length, it would be difficult for me to measure hair length with more than a tenth of an inch (2.4 millimeters) of accuracy. For hair data analysis, we need only around three or four digits of accuracy.

It is also worth noting at this point that these issues have nothing to do with JavaScript. Most, if not all, modern computers store and manipulate floating-point values using a standard established by the Institute of Electronic and Electrical Engineers (IEEE) in 1985. All programs that run on a computer will manipulate values in the same way, so floating-point numbers in JavaScript are no different from those in any other language.

The only difference between JavaScript floating-point values and those in other languages is that a floating-point variable in JavaScript occupies 8 bytes of memory, which is twice the size of the float type in the languages C, C++, Java, and C# (but not Python). A JavaScript floating-point variable equates with a double precision value in those languages.

Creating random dice

We can explore the difference between integer and floating-point values in JavaScript by creating a “random dice” web page. This will display a value between 1 and 6 when the user presses a button. JavaScript has a built-in library of Math functions including one called random, which generates a real number that ranges from 0 to 1 (but does not include the value 1). Let’s investigate how this works.

MAKE SOMETHING HAPPEN

Random numbers

Let’s have a look at random numbers in JavaScript. Start your browser and navigate to the page in the Ch04 Working with data\Ch04-02 Computer Dice folder. Press the button and note that you get a different dice roll each time.

Open the Developer View by pressing F12. You can begin by displaying a random number by calling the random function from the Math library:

> Math.random()

When you press Enter, JavaScript will calculate a “pseudorandom” number and display the result. The number is called “pseudorandom” because it is calculated as one of a sequence of values generated from a particular “seed” value. The seed value is chosen by JavaScript using the current time, so a program will get a different sequence each time it runs.

> Math.random()
<- 0.01479622790601498

I would be very, very surprised if you got the same number as the one printed above (you would have to run your program at exactly the same time I did). You will see a number between 0 and 1. Call random a few more times and note that you get a different number each time. If you tried it enough times, it is possible you could see a value 0 but you would never see a value of 1. That is important to us.

The random function returns a value between 0 and 1. We can expand the range of the random number by multiplying it by the range that we want; in this case, that range is 6. Try entering this:

> Math.random()*6

This will generate a result that ranges from 0 up to but not including 6 (because random() can never return 1). Try it.

> Math.random()*6
<- 1.342641962710725

The next thing we need to do is get rid of that fractional part. JavaScript provides another Math function, called floor, which chops the fractional off a number. No matter how large the fractional part, it is always discarded. Try this:

> Math.floor(1.9999)

The value 1.9999 is very close to 2, but the floor function throws away the entire fractional part. We can apply the floor function to our random value. Try this:

> Math.floor(Math.random()*6)

This is an important thing to learn. I can feed an expression into a function call. The above statement gets a value from the random function, multiplies it by 6, and then feeds the result into the floor function. If you repeat this statement lots of times, you should see the values 0, 1, 2, 3, 4, and 5 appearing at random. We want a value between 1 and 6, so we just add 1 to this:

Click here to view code image

> Math.floor(Math.random()*6)+1

This is the “brains” of our program. Click the Elements tab in the Developer View and then expand the <script> element to view the doRollDice function.

In the middle of the function there is a statement that sets the value of the spots variable to a random number between 1 and 6. How would you change the program to produce a number between 1 and 20?

Click here to view code image

> Math.floor(Math.random()*20)+1

This turns out to be very easy; the program must multiply the random value by 20 rather than 6.

Working with text

We now know how to use variables that hold numbers. A program can also create a variable that holds a string of text.

var customerName = "Fred";

This statement looks exactly like the statement we used to create the total variable except that the value being assigned is a string of text. The string being assigned is enclosed in double quote characters that define the limits of the text. The double quote characters are called delimiters because they define the limits of the text. The delimiters are not part of the string being stored, so the customerName variable just contains the word Fred.

The customerName variable is different from the total variable in that it holds text rather than a number. We can use this variable anywhere we would use a string.

Click here to view code image

var message = "the name is " + customerName;

In the expression being assigned, the text in the customerName variable is added onto the end of the "the name is " string. As customerName currently holds the string "Fred" (we set this in the previous statement), the above assignment would create another string variable called message, which contains "the name is Fred". We have seen that the + operator before when we used it to add numbers together. In this context it is performing concatenation, which means adding two strings together.

JavaScript string delimiters

The " character can act as a delimiter that marks the start and the end of a string in the program. But what if we want to enter a string that contains a " character? In that case, we can use a single quote (') to mark the start and end of the string:

Click here to view code image

var message = 'Read "Begin to code with JavaScript". It is an amazing book';

If you want to enter a string that contains both single and double quotes, you can use backticks (`)—also known as an acute—to delimit the string:

Click here to view code image

var message = `Read "Begin to code with JavaScript". It's an amazing book`;

If you have a need to enter a string that contains both kinds of quotes and backticks, then it must be an amazing string. You can enter that by using escape sequences.

Escape sequences in strings

You can include quote characters in a string by using an escape sequence. Normally, each character in a string represents that character. In other words, an A in a string means ‘A’. However, when JavaScript sees the escape character —the backslash (\) character—it looks at the text following the escape character to decide what character is being described. This is called an escape sequence. There are many different escape sequences you can use in a JavaScript string. The most useful escape sequences are shown in the following table.

Escape sequence

What it means

What it does

\\

Backslash character (\)

Enters a backslash into the string

\'

Single quote (')

Enters a single quote into the string

\`

Backtick (`)

Enters a single backtick into the string

\"

Double quote (")

Enters a double quote into the string

\n

Unicode Line Feed/New Line

End this line and take a new one

\t

Unicode Tab

Move to the right to the next tab stop

\r

Unicode Carriage return

Return the printing position to the start of the line

If you’re wondering what Unicode means, it is a mapping of numbers to character designs. We saw it in Chapter 2 in the “Display symbols” section.

Working with strings and numbers

You can create expressions involving strings, but the only operator that can be used between two strings is the + operator that we saw earlier. You can also create expressions involving strings and numbers, but you need to be a bit careful when you do this.

CODE ANALYSIS

Combining strings and numbers

We can find out more about how strings and numbers can be combined in a JavaScript program by using the Developer View to answer some questions.

Question: What happens if I add a number to a string?

Answer: We know that JavaScript regards numbers and strings as different types of data. Let’s see what happens when we add them together:

> "hello" + 99
<- "hello99"

This statement adds the numeric value 99 to the string “Hello”. JavaScript automatically converts the number into a string giving the result that you see above. However, this can lead to strange behavior if you add lots of numbers to a string…

Question: What happens if I add lots of numbers to a string?

Answer: The way that JavaScript performs the conversion of numbers to strings can result in some interesting consequences:

> 1 + 2 + "hello" + 3 + 4
<- "3hello34"

JavaScript works along the expression. It adds the 1 and the 2 to produce the value 3. Then it sees a string and thinks, “Oh. I need to make this number into a string.” It converts the value 3 into a string and adds it to “hello”. Then it converts everything else it finds into strings, too, and adds them together. If you want to force the calculations to be performed before the values are converted into strings, you can use brackets.

> (1+2) + "hello" + (3+4)
<- "3hello7"

Note that this is not the kind of programming I approve of, because it is a bit confusing. If I really wanted to create an output like what’s shown above, I would break it down into a number of separate statements.

var calc1 = 1 + 2;
var calc2 = 3 + 4;
var result = calc1 + "hello" + calc2;

This makes it very clear to the reader of my program that I wanted the values to be calculated before I displayed them.

Converting strings into numbers

We have seen that JavaScript regards numeric and text variables as different types of data. We have also seen that JavaScript will automatically convert from a number into a string when it thinks this is appropriate (although it may sometimes get this wrong). Sometimes our programs will need to convert from a string into a number. For example, we might want to create an adding machine web page. The user enters two values and presses a button, which causes the sum of the numbers to be displayed. Figure 4-7 shows how the page can be used to solve the age-old question “What is 2+2?”

Figure 4-7 Adding machine

The screenshot shows the source code in the element tab of the developer view. The function 'doRollDice()' is displayed when the script is expanded.

The page contains two input fields for the values to be entered, a button to request a calculation, and a paragraph element that displays the result. We know how to create almost every part of this application except for one thing. The user will enter the numbers to be added as text strings. We need a way of converting these strings into numbers that can be added together.

MAKE SOMETHING HAPPEN

Converting strings into numbers

JavaScript makes a distinction between numbers and values. Let’s investigate how this works. Open the web page in the example folder Ch04 Working with data\Ch04-03 Adding Machine. This displays an adding machine. Enter two numbers and press the Add Numbers button. Note that the right answer appears. Now press F12 to open the Developer View. Click the Console tab to view the console prompt. Type the following sum and press Enter:

> 2+2

The console shows the result of the expression you would expect:

<- 4

Now enter a different sum:

> "2"+"2"

This is adding the string "2" to the string "2".

<- 22

We can see this distinction in action when we create variables. Create the two variables by entering the following:

> var stringTwo = "2"
> var numberTwo = 2

JavaScript provides a function called typeof, which will tell you the type of a variable you supply to it. Use it to investigate the type of the variables name and age.

> typeof(stringTwo)
<- "string"
> typeof(numberTwo)
<- "number"

JavaScript provides a function called Number, which will attempt to convert whatever you give it into a number. Let’s use this to convert the string version of 2 into a number version:

> var convertedTwo = Number(stringTwo)

This statement creates a new numeric variable convertedTwo, which contains the number held in stringTwo. The type of convertedTwo is a number:

> typeof(convertedTwo)
<- "number"

Leave the Developer Tools window open for later.

Make an adding machine

Now that we know we can use the Number function to convert from a string type into a numeric type, we can create our adding machine. The HTML for the elements on the page is as follows:

The screenshot presents the source code to program a adding machine. The line, First number: <input type equals "text" id equals "no1Text" value equals "0"> is displayed to accept the second input number. The line, second number: <input type equals "text" id equals "no2Text" value equals "0"> is displayed to accept the second input number. The line, <input type equals "button" value equals "add numbers" onclick equals "doAddition();"> is displayed to trigger the calculation. The line < p id equals "resultparagraph "> represents the paragraph to display the answer.

You can map each of the elements in the HTML onto items on Figure 4-7. There are two text input areas for the user to type in the values that are to be added. These areas have IDs that are n1text and no2text. There is also an output paragraph that will be used to display the output. The output paragraph has the resultParagraph ID. When the user clicks the button, the function doAddition will be called to calculate the result and display it. This function takes the text out of the inputs, converts it into numbers, and then does the calculation.

The input element reads a string of text from the user. This works if we just want to read names. However, it is not so useful if we want to read in numbers.

The screenshot presents the source code to get user input and convert it to a number. The line, Var no1 element equals document.getElementById ("no1Text"); is displayed to get a reference to the element holding the user input. The line, Var no1Text equals no1Element1.value ; is displayed to get the text from the user input element. The line, Var no1number equals number (no1Text); converts the text into a number.

This is the code that gets the user input for the first value and converts it into a number that can be used in calculations. The Number function performs the conversion; the first two statements get a reference to the input element holding the number text and then get the text from that element. The program uses a similar sequence of statements to get the value entered in the second input element.

Click here to view code image

var result = no1Number + no2Number;

This is the statement that calculates the addition and stores it in a variable called result. This is the part of the program where the data processing is performed. The rest of the HTML and JavaScript are there to provide a means of input and output. The last thing the function needs to do is display the result for the user. We have written several functions that do this; the result is displayed by modifying the text in a paragraph on the web page.

Click here to view code image

var resultElement = document.getElementById("resultParagraph");
resultElement.innerText = result;

The first statement gets a reference to the resultParagraph element. The second statement sets the innerText to the value of the result that was calculated. Note that the result variable holds a number, but JavaScript will automatically convert this to text for display. You have seen this automatic conversion of numbers to text before.

WHAT COULD GO WRONG

Entering invalid numbers

When you create a program, you have to think of ways that it could go wrong. For example, after being asked to type 2 into a text entry in our adding machine, it is perfectly possible for a user to type this instead:

We are using the function Number to convert text into a numeric value. It would be very impressive if the Number function could convert “two” into the value 2, but unfortunately it can’t. Instead, it decides that “two” is not a number, and so it returns NaN, which means “not a number.” Any JavaScript calculations involving something that is not a number generate a result of NaN, so an attempt to use text like this would result in the display below:

The good news is that at least the program didn’t output a number like -8399608 when the user upset it like this, but it is still less than perfect. In the next chapter, we will discover how a program can decide when a number is valid and display a suitable alert message. However, the best way to remove an error like this is to do something that ensures it can never happen. We can tell the browser that a given input element is a number rather than text.

Click here to view code image

First number: <input type="number" id="no1Text" value="0">

The HTML above shows how we do this. The type of the input is now number. If we do this, the input element will only accept numbers when the user types things into it. If you used this input area on your smartphone, you’d be given a numeric keypad to enter the value, rather than a full keyboard. On a Windows PC, the Microsoft Edge browser even shows up and down buttons that you can use to change the numeric value of the element.

Note that even though we have specified that the type of the input field is number, we still get a text string from the input field when we use it in our programs. However, we can be sure that the text that we get from the element only contains digits. You can try this version of the page in the Ch04 Working with data\Ch04-04 Number Adding Machine example folder.

PROGRAMMER’S POINT

Error handling is a big part of programming

Professional programmers spend at least as much time thinking about how things can go wrong as they do writing program code. They also spend a lot of time deciding how they can prove that their program works by testing it. This is one reason why what look like simple programs can take a long time to create.

Making applications

We now know enough programming to be able to make some useful applications, so let’s make some.

Calculating a pizza order

Rigorous scientific research conducted by me at many hackathons I’ve attended has arrived at a figure of exactly 1.5 people per pizza. In other words, if I get 30 students, I’ll need 20 pizzas, and so on. I decided to make a web page that works out how many pizzas I need to order for a given number of students. The user types in the number of students and presses the Calculate Pizzas button to display the result. The code for my first version is shown below, and the result is shown in Figure 4-8.

The screenshot shows the source code to program a pizza calculator. The line, < link rel equals "stylesheet" href equals "styles.css"> is displayed to add some style. The line, number of students: < input type equals "number" id equals "noOfStudentsText" value equals "0"> is displayed to input elements for the number of students. The line, <input type equals "button" value equals "calculate pizzas" onclick equals "doPizzaCalc();"> is displayed to get the result. The line, function doPizzaCalc() is displayed to calculate the result.

Figure 4-8 Pizza calculator

The screenshot shows the source code to perform the calculation in pizza calculator. The line, var noOfStudents equals Number (noOfStudentsText); is displayed to get the number of students. The line, var noOfPizzas equals noOfStudents over 1.5; is displayed to perform the calculation. The line, var resultElement equals document.getElementById ("result paragraph"); is displayed to get the paragraph that displays the result. The line, var ResultElement.innerText equals "you need" plus noOfPizzas plus "Pizzas."; is displayed to display the result.

This is my first version. I’m using the Pizza emoji symbol (&#x1f355;) to get a nice pizza slice for the heading. The page works fine with the data above. If I say there are 30 students, the program will tell me I need 20 pizzas. However, there are problems with some numbers of pizzas, as you can see in Figure 4-9.

Figure 4-9 Pizza fractions

I can’t ask the pizza place for a fraction of a pizza, so I need a way of converting the number of pizzas to an integer. At this point, I also must decide what the conversion will do. If I just use the floor function we used in the dice program, this will result in an order for 26 pizzas because the floor function truncates the floating-point value. This effectively means that I’ll have pizza for only 39 people rather than 40, leaving one hungry student. There are several ways to address this problem. I might think the best way to attack the problem is to add one extra pizza to the order to take care of any “spares.”

Click here to view code image

var noOfPizzas = Math.floor(noOfStudents / 1.5) + 1;

MAKE SOMETHING HAPPEN

Fix the pizza program

Load the example program in the folder Ch04 Working with data\Ch04-05 Pizzacalc Version 1 and modify it using the above statement so that when you tell it there are 40 students, the program suggests that you buy 27 pizzas. Then change the program to make it less generous. Make the program always round down to the nearest integer number of pizzas to order. You can find my generous version in Ch04 Working with data\Ch04-05 Pizzacalc Version 2.

The program uses a style sheet to modify the style of the <h1> and <p>. You could modify these styles to make it look even better.

PROGRAMMER’S POINT

Never assume that you know what a program is supposed to do

If you wrote the pizza calculator for a customer, you should not decide for yourself what the program should do if it must order a fraction of a pizza. Your customer might want to “round down” the number of pizzas to keep their costs down. If this is the case, they will complain when your program adds an extra pizza. Alternatively, they might want to establish a reputation as a generous person, in which case the program should be made to “round up” the value.

As a programmer, never assume that you know what the program should do. You must always ask the customer. Otherwise, you might find yourself paying for over-ordered pizzas.

Converting between Fahrenheit and centigrade

An interesting thing about the adding machine program and the pizza calculator is that they have similar structures. The adding machine takes an additional input (the second number to be added), but the way that it works is just the same as the pizza calculator. We can use this same pattern to make a third program that converts temperature readings between Fahrenheit and centigrade. Have a go at creating a conversion web page. The following sections offer some hints.

Conversion formula

To convert a temperature from Fahrenheit to centigrade, you subtract 32 from the Fahrenheit value and then divide the result by 1.8. The statement below shows how this would work. It assumes that you have created a variable called fahrenheit that contains the temperature in Fahrenheit.

Click here to view code image

var centigrade = (fahrenheit-32)/1.8;

Truncating the displayed temperature value

We saw in the pizza calculator example that JavaScript likes to display lots of decimal places when it shows you a number. It would be distracting if the program displayed 60 degrees Fahrenheit as 15.55555555 degrees Centigrade. The toFixed method can be used on a numeric variable to create a string with a particular fixed number of decimal places. The statement below would create a variable called resultString that contains a number string that only contains one decimal place. In other words, a temperature of 15.5555555 would be converted to a string containing 15.6.

Click here to view code image

 var resultString = centigrade.toFixed(1);

Displaying a thermometer emoji

You might want to add a thermometer emoji to your web page. This requires you to add two symbols to your HTML source. The HTML below will display a heading with a thermometer emoji.

Click here to view code image

<h1>&#x1f321;&#xfe0f; Fahrenheit to Centigrade</h1>

You can find my version of the solution in this folder: Ch04 Working with data\Ch04-07 Fahrenheit to Centigrade. You can now write any kind of conversion program you like, converting feet to meters, grams to ounces, or liters to gallons.

Adding comments

As soon as you start to make useful programs, I think you should start adding comments to make it clearer what your program is doing. You don’t write comments for the computer; you write comments for someone reading your program:

Click here to view code image

/* Based on each pizza feeding 1.5 students. We divide the number
   of students by 1.5 to get the number of pizzas. Then we drop
   the fractional part and add 1 to round up the number
   Note that this means we might buy slightly too much
   pizza for some numbers of students.
*/
var noOfPizzas = Math.floor(noOfStudents / 1.5) + 1;

The comment in the program above makes it very clear exactly how we are calculating the number of pizzas and the reasoning behind the statement. If the comment weren’t there, you’d have to know that 1.5 was there because we have decided that is how many students each pizza will feed. You can write a comment that spreads over several lines by enclosing your comment text in the characters /* and */. When the browser sees the character sequence /* in a JavaScript program, it ignores the following text, up to the point where it sees a */ that ends the comment text. You can put comments anywhere in your program. The browser will completely ignore them. You can also create single-line comments:

Click here to view code image

var centigrade = (fahrenheit-32)/1.8; // using standard conversion formula

The comment above is a single-line comment. It starts at the character sequence // and finishes at the end of that line. We can add these kinds of comments on the end of a statement or on a line by themselves. If you use Visual Studio Code to write your programs, you’ll find that comments are displayed in green to make them stand out.

It is important that programs be written in a way that makes it easy for humans to understand what is going on. We have seen that when choosing identifiers for variables we need to make sure that the name describes what the variable is being used for. We can also make programs clearer by adding comments.

Some people say that writing a program is a bit like writing a story. I’m not completely convinced that this is true. I have found that some computer manuals are works of fiction, but programs are something else. I think that while it is not a story as such, a good program text does have some of the characteristics of good literature:

It should be easy to read. At no point should the hapless reader be forced to backtrack or brush up on knowledge that the writer assumes is there. All the names in the text should impart meaning and be distinct from each other.

It should have good punctuation and grammar. The various components should be organized in a clear and consistent way.

It should look good on the page. A good program is well laid out. The different parts should be indented, and the statements spread over the page in a well-formed manner.

It should be clear who wrote it and when it was last changed. If you write something good, you should put your name on it. If you change what you wrote, you should add information about the changes that you made and why.

A big part of a well-written program is the comments that the programmer puts there. A program without comments is a bit like an airplane that has an autopilot but no windows. There is a chance that it might take you to the right place, but it will be hard to tell where it is going from the inside.

Be generous with your comments. They help to make your program much easier to understand. You will be surprised to find that you quickly forget how you got your program to work. You can also use comments to keep people informed of the particular version of the program, when it was last modified and why, and the name of the programmer who wrote it—even if it was you. From now on, the example code that you see will have what I consider an appropriate level of comments.

PROGRAMMER’S POINT

Don’t add too much detail in your comments

Writing comments is a very sensible thing to do, but don’t go mad. Remember that the person who is reading your program can be expected to know JavaScript and doesn’t need things explained to them in too much detail:

Click here to view code image

goatCount = goatCount + 1; // add one to goatCount

This is plain insulting to the reader, I reckon. If you chose sensible names, you should find that quite a lot of your program will express what it does directly from the code itself.

HTML comments

Note that these comments only work in the <script> part of the program. You can add comments to the HTML, as we saw in Chapter 2, but you use a different character sequence to mark the start and end of the comments:

Click here to view code image

<!-- Rob's Pizza Calculator Page Version 1.0 -->

The start of the comment is marked by the sequence <!-- and the end of the comment by the sequence -->. As with JavaScript comments, the text between the two sequences is ignored by the browser.

Global and local variables

At the start of this section, we wanted to make a totalizer program that can be used to add up a bunch of numbers. We can now create this. Let’s assume that we are creating a solution for a customer who really does want to totalize some numbers. You have sat down with her and agreed on the following design for the application.

Figure 4-10 Totalizer

The screenshot displays a field, which allows the user to enter values to add. The entered values is 0. The result is displayed at the bottom which reads "total is 0." The 'add to total' and 'set total to 0' buttons are also displayed.

Your customer would like a stylish black background containing the Abacus emoji. We can create this by using a style sheet that sets the color scheme for the application and finding the symbol number for the abacus (&#x1f9ee;).

She wants to be able to type in a value and press the Add to total button to add the value to the total. She also wants a button she can use to set the total back to zero when she has finished adding one set of values. You agree on the design shown in Figure 4-10 above.

PROGRAMMER’S POINT

Getting a good specification is vital

The sample page shown in Figure 4-10 is a good start for the specification of the Totalizer application. It is very important that you get a solid specification for any work that you perform, even (or perhaps especially) if you are working for someone you know. The nice thing about the screenshot of the application is that it sets out exactly what the solution should look like. However, there are some questions I’d want answered, too.

I would like to know if there is any upper limit to the amount to be added to the total. I’d also like to know if the Totalizer should accept negative numbers to be subtracted from the total or whether the total should always be increased. The answers to these questions tell me whether the Totalizer should detect and reject invalid input values. The customer might be assuming that negative values should not be added (or might never have thought about this issue). Either way, as the builder of the solution, you need to know how it should work. Otherwise, you might end up having conversations with your customer that include phrases such as, “It isn’t supposed to do that…”.

Global variables

The Totalizer program is interesting because it is the first program we have written that needs to “remember” something between function calls. Until now, every program that we have created takes data from the input elements, does something to it, and then displays the result. Any variables that we have created to store data in a function during data processing are discarded as soon as the process has finished. For example, consider the temperature conversion program, which takes a temperature entered in Fahrenheit and converts it to centigrade.

A screenshot displays the global variables. The line, var FahrenheitElement equals document.getElementById("FahrenheitText"); gets a reference to the input element. The line, Var FahrenheitText equals FahrenheitElement.value; gets the text from the input element. The line, var Fahrenheit equals number left parenthesis FahrenheitText); converts the text into a numerical value. The line, var centigrade equals (Fahrenheit minus 32) over 1.8; is displayed to convert the value into centigrade. The line, var resultElement equals document.getElementById("resultParagraph") gets a reference to the output element. The line, var resultString equals centigrade.to Fixed(1) plus "degrees Centigrade"; is displayed to build the complete the result string. Tle line, resultElement.innerText equals resultString; put the result string on the output element.

All the variables in this function will be destroyed once the function has finished. They are described as local because they are local to the function. This is how the JavaScript manages variables created using var. Most of the time, this is exactly what you want. We don’t want the program to use any values left over from a previous use of the function. However, the Totalizer program needs to retain the total value for use in successive calls of the function that adds values to it. In other words; we want to write some code like this:

Click here to view code image

var total=0; // Global variable to hold the total

/* This function reads the value from the valueText element
   and adds it to the global total value */
function doAddToTotal() {

  var valueElement = document.getElementById("valueText");
  var valueText = valueElement.value;
  var value = Number(valueText);

  total = total + value; // update the global total value

  // Display the updated total
  var resultElement = document.getElementById("resultParagraph");
  var resultString = "Total is " + total;
  resultElement.innerText = resultString;
}

The variable total is special. It exists outside any JavaScript functions. We call it a global variable because it can be used by any function in my application. I’ve added a comment above the declaration of the total variable. This is because I like my global variables to stand out in the code.

PROGRAMMER’S POINT

Global variables are a necessary evil

If you talk to some programmers, they might tell you that your programs should never use global variables. This is because a global variable represents a possible failure point that is out of your control. I can be sure that all the variables in my functions contain correct values. This is because each time a function runs, it makes clean new copies of every variable, but a global variable exists in outside my functions. I can’t regard it as “clean” because I don’t know what other functions might have been doing with it. Mistakes by other programmers could make my functions do the wrong thing, and that is bad. If another function changes, the contents of total my function could display a result that is incorrect. However, in the case of the Totalizer program, a global variable is the simplest way I can make it work.

Programmers talk about functions having side effects. These are things that the function does that change the state of the system in which they are running. In the case of the Totalizer, the doAddToTotal function has a side effect that increases the value of total by the amount entered by the user. This is a side effect that is present by design. It is important to avoid unintended side effects.

CODE ANALYSIS

Global variables and side effects

It is important that you understand the difference between local and global variables, so here are some questions you might have considered.

Question: How can I tell if a variable is global?

Answer: A global variable is declared outside of any function. The total variable below is not part of any function, therefore it is global. The variable is also set to 0 when it is created.

var total=0;

In Chapter 3, in the “Create a ticking clock” section, we discovered a JavaScript function called onload, which runs when a web page is loaded. A program could initialize (but of course not declare) global variables in that function.

Question: Is the value of a global variable retained if I reload the web page?

Answer: No. When the page is reloaded, the JavaScript environment is reset and new global variables are created.

Question: Is a single global variable shared between multiple tabs of the same page being viewed in a single browser? In other words, if I opened several views of the Totalizer program, would the value of total be shared between them?

Answer: No. Each web page runs a separate JavaScript environment.

Question: Do any other functions in the Totalizer have side effects?

Answer: Yes. The function that is called to clear the total back to 0 will set the value of total back to 0.

Click here to view code image

/* This function clears the total value and updates the display
*/
function doZeroTotal(){
  total=0; // set the global total to 0

  // update the display
  var resultElement = document.getElementById("resultParagraph");
  resultElement.innerText = "Total is 0";
}

This function sets the value of total to 0 and then updates the display to reflect this.

Question: How could I create a Totalizer that stored the total value when the page was not being used?

Answer: The browser provides a feature called “local storage,” which can be used to store values when a web page is not active. In Chapter 9, we will use this to create an address book. A totalizer program could use local storage to hold a total value that would persist when the totalizer page was not being used.

You can find my version of the Totalizer program in the Ch04 Working with data\Ch04-08 Totalizer folder. This includes the style sheet that sets up the requested color scheme.

MAKE SOMETHING HAPPEN

Make some party games

There is no better way to show off your programming skills than by using them to make some silly party games. At least, that’s what I think. We can create a good-looking party game using our skills with CSS and JavaScript. The basis of many games is randomness. We know how to use JavaScript to create random numbers, so let’s see if we can make some games using this.

“Nerves of Steel”

We can use our ability to make random numbers, coupled with the setTimeout function we used to make egg timers in Chapter 2, to create a “Nerves of Steel” party game. The game works like this:

One player presses the Start Game button.

The program displays Players stand.

The program then pauses for a random time between 5 and 20 seconds. While the program is paused, players can sit down. The players need to keep track of the last person to sit down.

When the time interval expires, the program displays “Last to sit down wins.” Players still sanding are eliminated, and the winner is the last person to sit down.

This is a variant of the egg timer program from Chapter 2. Rather than set a timeout for a fixed duration (5 minutes), the program selects a random time for the duration. You can make the game properly skillful if the game displays the selected time at the start of the game. You can also improve it using sound effects to mark the start and end of the timeout session.

High and Low

Another way of using random numbers is to create a “High and Low” game. The game works like this:

One player presses the Next Round button.

The program displays a number between 1 and 10, inclusively.

The program then sleeps for 20 seconds. While the program is asleep, the players are invited to decide whether the next number will be higher or lower than the number just printed. Players who choose “high” stand on the right. Players who choose “low” stand on the left.

The program then displays a second number between 1 and 10, and anyone who was wrong is eliminated from the game. The program is then re-run with the players that are left until you have a winner.

This game can get very tactical, with players taking a chance on an unlikely number just so that they will be one of the people to go forward to the next round.

Adding sound

You can add sound to the game. You can have a ticking clock sound effect while the players are waiting and a “ding” sound when the timer expires. To do this the program will have to start and stop the audio playback. It will also have to “reset” the ticking sound so that it plays from the beginning of the sound sample. A sound in HTML provides play and pause methods that can be used to control playback. It also provides a currentType property that a program can use to read or set. This is the tickAudio element in my version of the program:

Click here to view code image

<audio id="tickAudio">
   <source src="tick-track.mp3" type="audio/mpeg">
</audio>

I can start the playback as follows. The first statement sets the playback position at 0 so that the playback begins at the start of sound. The second statement plays the sample.

Click here to view code image

tickSoundElement.currentTime=0;
tickSoundElement.play();

When I want the ticking sound to stop (when the timer has expired), I use the following:

tickSoundElement.pause();

Note that there is no command to stop the playback of a sound. You can find my versions of the games in the folders Ch04 Working with data\Ch04-09 Nerves of Steel and Ch04 Working with data\Ch04-10 High and Low. You can use these as the basis of any other games you might like to create.

What you have learned

This chapter has given you a good understanding of how JavaScript programs store and manipulate data. Here are the major points you have covered in the chapter:

A computer is fundamentally a data processor. A program receives data, does something with it, and outputs more data. What the computer does with the data is determined by the program itself.

The JavaScript programs that we have created take data in from input elements and display data by updating the text displayed by a paragraph element.

Data processing in a computer is performed by the evaluation of expressions. An expression contains operands (values to be worked with) and operators (which specify what is to be done with the operands). In the expression 2+3 the operands are the literal values 2 and 3. The operator is +.

A program is unaware of the nature of the data that it is processing. Meaning is added when humans interpret the data as information.

A variable is a named storage location that holds a value that a program is working with. Variables can be created using var.

Variables can be used as operands in expressions. The assignment operator is used to set a value in a variable.

Variables can be created before they are used, in which case, they contain a value denoted as “undefined.” When assigned to a value, a variable will acquire a type appropriate to the value. The two types we have used so far are number (a numeric value) and string (a string of text)

Operators in an expression are evaluated according to their priority. This priority can be overridden by using brackets.

Numbers in a program can be real numbers (with a fractional part) or whole numbers (integers). JavaScript provides Math functions for creating whole numbers from floating point numbers. The floor function removes the fractional part, whereas the round function rounds up to the nearest whole number.

Text in program source code can be delimited by the double quote ("), single quote ('), or backtick (`) characters. Escape characters (\)are used in strings for the entry of delimiter characters and some nonprinting characters.

If an expression involves string and numeric values, the numeric values are automatically converted into strings.

The JavaScript function Number is used to convert a string into a numeric value. If this conversion is not possible, the Number function returns the value NaN (not a number). All numeric calculations involving the value NaN will generate a result of NaN.

Comments can be added to a program by delimiting them with /* and */ character sequences. A single-line comment is started by the character sequence // and extends to the end of the line containing the comment.

A variable is made global by declaring it outside any JavaScript function. Global variables are useful because they allow values to be shared between functions, but they should be used with care as they represent a way in which a fault in one function could set a global variable to a value, which could cause other functions to fail. Changes made by a function to the contents of a global variable are known as “side effects.”

To reinforce your understanding of this chapter, you might want to consider the following “profound questions” about variables.

Do all computer programs have to have an input from the user?

Many programs have an input from the user that they use to produce an output. However, not all programs have an input. The “Nerves of Steel” and “High and Low” games get their input from random numbers before displaying them.

What is the difference between “undefined” and “not a number”?

A JavaScript variable normally holds a value. However, it can also hold the special values undefined and NaN (not a number). A variable is “undefined” if it has been created but it has not been assigned a value yet. The value NaN (not a number) is used to represent a situation when a calculation did not create a numeric result. The Number function is used to convert a string of text into a number and will return a result of NaN if conversion was impossible because the supplied string does not contain digit characters.

Do long variable names slow my program down?

No, but they do speed up the process of understanding what the program does.

What is the difference between an operator and an operand?

An operator is a doing thing (in the English language the verbs are a bit like the operators). An operand is the thing that is operated on. In the sentence “The cat sat on the mat,” I would say that the operands are “cat” and “mat,” and the operator is “sat.”

What is the difference between a real number and a whole number?

A real number has a fractional part. The value of Pi is a real number as it has a fractional component (3.1416). A whole number has no fractional part. Whole number values are used in programs for things like counting (how many sheep in a field). Real numbers are used for calculated values (the average weight of the sheep in a field).

What is the length of the longest string that a program can hold?

A string can be very, very long. You could store an entire book in a single string if you wish.

Can I create a global variable inside a JavaScript function?

No. The important thing about a global variable is that it exists outside all functions. The variables created inside a function body are discarded when the function stops running. However, we sometimes need variables whose value is persisted between function calls. These are declared as global and can be accessed by all functions.

How can I create a string that contains the double quote characters that delimit it?

My programs usually use double quotes to mark the start and end of strings in the program text. If I want to include a double quote in the string there are two ways I can do this. The first is to use an escape sequence (\") in the string. The other way would be to use either single quote (') or back tick (`) to delimit the string with the double quote characters in it.

5
Making decisions in programs

What you will learn

I’ve described a computer as a sausage machine that accepts an input, does something with it, and then produces an output. This is a great way to start thinking about computers, but a computer does a lot more than that. Unlike a real-life sausage machine, which simply tries to create sausage from anything you put in it, a computer can respond to different inputs in different ways. In this chapter, you’ll learn how to make your programs respond to different inputs. You’ll also learn about the responsibility that comes with making the computer work in this way because you must be sure that the decisions your programs make are sensible.

Boolean thinking

The if construction

Use decisions to make an application

Improve the ride selector

What you have learned

Boolean thinking

In Chapter 4, you learned that programs use variables to represent different types of data. I like to think that you will forever associate the number of hairs on your head with whole numbers (integers) and the average length of your hair with real numbers (floating-point values). Now it’s time to meet another way of looking at data values: Boolean. Data that is Boolean can only have one of two values: true and false. You could use a Boolean value to represent whether a given person has any hair.

Boolean values in JavaScript

A program can create variables that can hold Boolean values. As with other JavaScript data types, JavaScript will deduce the type of a variable from the context in which it is used.

var itIsTimeToGetUp = true;

The above statement creates a variable called itIsTimeToGetUp and sets its value to true. In my world, it seems that it is always time to get up. In the highly unlikely event of me ever being allowed to stay in bed, we can change the assignment to set the value to false:

var itIsTimeToGetUp = false;

The words true and false are keywords. These are words that are “built in” to JavaScript. There are 63 different keywords. You’ve already seen a few of them. For example, function is a keyword. When JavaScript sees the keywords true or false, it thinks in terms of Boolean values.

JavaScript regards values that are numbers or text as being either “truthy” or “falsy.” Values are regarded as “truthy” unless they are zero, an empty string, Not a Number (NAN), or undefined—in which case, they are “falsy.”

CODE ANALYSIS

Boolean values

Boolean values are a new type of data that a program can manipulate. But of course, we have questions about them.

Question: What do you think would happen if you displayed the contents of a Boolean value?

alert(itIsTimeToGetUp);

Answer: When you display any value, JavaScript will try to convert that value into something sensible for us to look at. In the case of Boolean values, it will display true or false.

Question: Is there a JavaScript function called Boolean that will convert things into Boolean values, just like there is a Number function that will convert things into a number?

Answer: Indeed, there is. The Boolean function applies the rules of “truthy” and “falsy” to the value supplied to it.

> Boolean(1);
<- true
> Boolean(0);
<- false

Applying Boolean to 0 gives the result false. Any other numeric value would be regarded as true.

Question: Are negative numbers regarded as false?

Answer: No. It is best to regard “truthy” as meaning “the presence of a value” rather than something that is positive or negative. Applying Boolean to a negative number will produce a result of true.

> Boolean(-1);
<- true

Question: Is the string false regarded as true?

Answer: Yes. If you understand this, you can call yourself a “truthy ninja.” Any string other than an empty string is regarded as true.

> Boolean("false");
<- true
> Boolean("");
<- false

Question: Is the value infinity regarded as true or false?

Answer: In our first encounter with JavaScript in Chapter 1, we tried dividing 1 by zero to see what happened. We discovered that this type of invalid calculation produces a value of infinity as a result. The best way to discover whether infinity is true or false is to ask JavaScript:

> Boolean(1/0);
<- true

The calculation 1/0 generates a result of infinity, which is regarded by the Boolean function as true.

Question: We know that if we ask JavaScript to perform a silly calculation, such as dividing a number by a string, the result is a special value called Not a number (NaN). Is NaN regarded as true or false?

Answer: JavaScript regards NaN as false. Dividing the number 1 by the string Rob produces NaN as a result. If we feed this into the Boolean function, it decides this value is false.

> Boolean(1/"Rob");
<- false

Question: What happens if a program combines Boolean values with other values?

Answer: In Chapter 4, in the section “Working with strings and numbers,” we discovered that when we combine numbers with strings, the numeric value is automatically “promoted” to a string. Something similar happens when logical values are combined with values of other types. A value that is true equates to the number 1 and the true string. A value of false equates to 0 and false.

> 1 + true;
<- 2
> "hello" + true;
<- "hellotrue"

Note that, as with numbers, this conversion does not work the other way. Just as we had to use the Number function to convert a string into a number, we have to use the Boolean function to convert values of other types into values that obey the “truthy” and “falsy” rules.

In Chapter 3, we created a ticking clock that displayed the time. The program in Chapter 3 used the Date object that JavaScript provides to get the current date and time:

Click here to view code image

var currentDate = new Date();
var hours = currentDate.getHours();
var mins = currentDate.getMinutes();
var secs = currentDate.getSeconds();

The statements above get the hours, mins, and secs values for the current time. We could use these values to write some JavaScript that would decide whether I should get up. Note that the hours value is supplied as a 24-hour clock value, meaning it goes from 0 to 23 over the day.

Boolean expressions

We’ve said that JavaScript expressions are made up of operators (which identify the operation) and operands (which identify the items being processed). Figure 5-1 shows our first expression, which worked out the calculation 2+2.

Figure 5-1 An arithmetic operator

An expression can contain a comparison operator, as shown in Figure 5-2.

Figure 5-2 A comparison operator

An expression containing a comparison operator evaluates to a result that is either true or false. The > operator in this expression means “greater than.” If you read the expression aloud, you say “hour greater than six.” In other words, this expression is true if the hour value is greater than 6. I need to get up after 7, so this is what I need for my alarm clock. Expressions that return either true or false are called logical expressions.

Comparison operators

These are the comparison operators that you can use in JavaScript programs.

Operator

Name

Effect

>

Greater than

True if the value on the left is greater than the value on the right

<

Less than

True if the value on the left is less than the value on the right

>=

Greater than or equals

True if the value on the left is greater than or equal to the value on the right

<=

Less than or equals

True if the value on the left is less than or equal to the value on the right

==

Equality

True if the value on the left and the value on the right can be promoted to values that are equal

===

Identity

True if the values on the left and the value on the right are the same type and hold the same value

!=

Not equals

True if the value on the left and the value on the right cannot be promoted to values that are equal

!==

Not identical

True if the values on the left and the value on the right are not the same type or do not hold the same value

A program can use comparison operators in an expression to set a Boolean value.

itIsTimeToGetUp = hours > 6;

This statement will set the variable itIsTimeToGetUp to the value true if the value in hours is greater than 6 and false if the value in hours is not greater than 6. Remember that an operator that is a single equals character performs an assignment, not a test. If this seems hard to understand, try reading the statement and listen to how it sounds. The statement “itIsTimeToGetUp equals hour greater than six” is a good explanation of the action of this statement.

CODE ANALYSIS

Examining comparison operators

Question: How does the equality operator work?

Answer: The equality operator evaluates to true if the two operands hold the same value.

> 1==1;
<- true

The equality operator (==) can be used to compare strings and Boolean values, too.

> "Rob"=="Rob";
<- true
> true == true;
<- true

We’ve seen that JavaScript “promotes” values when they are used in expression. This happens with the equality operator, too. The logical value true is promoted to the value 1 when it is used in an expression with the equality operator.

> 1 == true;
<- true

JavaScript returned true because the value true was promoted to 1 before the comparison was performed. Note that comparing true for equality with any other value would return false, because true is always promoted to 1.

> 2 == true;
<- false

Question: What is the difference between equality and identity?

Answer: We’ve just seen how the == (equality) operator above promotes values before comparing them. This means that the operator can compare values of different types.

> true == 1;
<- true

In the example above, the statement compares a logical value with a number. This generates a true result because the true value is “promoted” to the integer value 1 before being compared.

The identity comparison === does not perform any promotion before comparing two values. If we use the identity comparison to compare the logical value of true with 1, a result of false is produced.

> true === 1;
<- false

JavaScript returned false because once side of the identity operator holds a logical value (true), and the other holds a number (1). If, like me, you are the kind of programmer who thinks that programs should never compare numbers and logical values for equality and get a result of true (because comparing numbers and logical values directly is not a meaningful thing to do), then you can use the === comparison operator to make sure of this.

Question: How do I remember which relational operator is which?

Answer: When I was learning to program, I associated the < in the <= operator with the letter L, which reminded me that <= means “less than or equal to.”

Question: Can we apply relational operators between other types of expressions?

Answer: Yes, we can. If a relational operator is applied between two string operands, it uses an alphabetic comparison to determine the order.

> "Alice" < "Brian";
<- true

JavaScript returned true because the name Alice appears alphabetically before Brian.

WHAT COULD GO WRONG

Equality and floating-point values

In Chapter 4, we saw that a floating-point number is sometimes only an approximation of the real number value our program is using. In other words, some numbers are not stored precisely.

This approximation of real number values can lead to serious problems when we write programs that test to see whether two variables hold the same floating-point values. Consider the following statements, which I’ve typed into the Developer View in the Edge browser:

> var x = 0.3;
> var y = 0.1 + 0.2;

These statements create two variables, x and y, which should both hold the value 0.3. The variable x has the value 0.3 directly assigned, whereas the second variable, y, gets the value 0.3 as the result of a calculation that works out the result of 0.1 + 0.2. What do you think we will see if we test the two variables for equality?

> x == y;
<- false

This expression uses the equality operator (==), which will produce a result of true if its two operands hold the same value. However, JavaScript decides that x and y are different because the variable x holds the value 0.3, and the variable y holds the value 0.30000000000000004. This illustrates a problem with program code that compares floating-point values to determine whether they are equal. The tiny floating-point errors mean values we think are the same do not always evaluate that way.

If a program needs to compare two floating-point values for equality, the best approach is to decide they are equal if they differ by only a very small amount. If you don’t do this, you might find that your programs don’t behave as you might expect.

The date and time values returned from the JavaScript Date object are supplied as integers so you can test these for equality without problems.

Logical operators

At the moment, my test to determine whether it is time to get up is only controlled by the hour value of the time.

itIsTimeToGetUp = hours > 6;

The above statement sets the value of itIsTimeToGetUp to true if the hour is greater than 6 (meaning from 7 and onward) but we might want to get up at 7:30. To be able to do this, we need a way of testing for a time when the hour is greater than 6 and the minute is greater than 29. JavaScript provides three logical operators we can use to work with logical values. Perhaps they can help solve this problem.

Operator

Effect

!

Evaluates to True if the operand it is working on is False

Evaluates to False if the operand it is working on is True

&&

Evaluates to True if the left-hand value and the right-hand value are both True

||

Evaluates to True if the left-hand value and the right-hand value are both True

The && (and) operator is applied between two Boolean values and returns true if both values are true. There is also an || (or) operator, which is applied between two Boolean values and returns true if one of the values is true. The third operator is the operator ! (not), which can be used to invert a Boolean value.

CODE ANALYSIS

Logical operators

We can investigate the behavior of logical operators by using the Developer View in the Edge browser. We can just type in expressions and see how they evaluate. Please don’t be confused by the way that the < and > characters are used in the devleoper console samples below.

Question: What does the following expression evaluate to?

<- !true;

Answer: The effect of ! is to invert a Boolean value, turning the true into a false.

> !true;
<- false

Question: What does this expression evaluate to?

> true && true;

Answer: The operands on each side of the && are true, so the result evaluates to true.

> true && true;
<- true

Question: What does this expression evaluate to?

> true && false;

Answer: Because both sides (operands) of the && (and) operator need to be true for the result to be true, you shouldn’t be surprised to see a result of false here.

> true && false;
<- false

Question: What does this expression evaluate to?

> true || false;

Answer: Because only one side of an || (or) operator needs to be true for the result to be true, the expression evaluates to true.

> true || false;
<- true

Question: So far, the examples have used only Boolean values. What happens when we start to combine Boolean and numeric values?

> true && 1;

Answer: It turns out that JavaScript is quite happy to use and combine logical and numeric values. The above combination would not return true, however. Instead, it will return 1.

> true && 1;
<- 1

This looks a bit confusing, but it gives us an insight into how JavaScript evaluates our logical expression. JavaScript will start at the beginning of a logical expression and then work along the expression until it finds the first value it can use to determine the result of the expression. It will then return that value.

In the above expression, when JavaScript sees the left-hand operand is true, it says to itself “Aha. The value of the && (and) expression is now determined by the right-hand value. If the right-hand value is true, the result is true. If the right-hand value is false, the result is false.” So the expression simply returns the right-hand operand. We can test this behavior by reversing the order of the operands:

> 1 && true;
<- true

We know that any value other than 0 is true, so JavaScript will return the right-hand operand, which in this case is True. We can see this behavior with the || (or) operation, too. JavaScript only looks at the operands of a logical operator until it can determine whether the result is true or false.

> 1 || false;
<- 1
> 0 || True;
<- True

You might wish to experiment with other values to confirm that you understand what is happening.

We want to make some JavaScript that takes in hour and minute values and decides whether to sound the alarm. We could try to make an alarm that triggers after 7:30 by writing the following statement:

Click here to view code image

var itIsTimeToGetUp= hours>6 && minutes>29;

The && (and) operator is applied between the result of two Boolean expressions and returns true if both of the expressions evaluate to true. The above statement would set the variable itIsTimeToGetUp to true if the value in hours is greater than 6 and the value in minutes is greater than 29, which you might think is what we want. However, this statement is incorrect. We can discover the bug by designing some tests:

Hours

Minutes

Required Result

Observed Result

6

00

False

False

7

29

False

False

7

30

True

True

8

0

True

False

The table shows four times, along with the required result (what should happen), and the observed result (what does happen). One of the times has been observed to work incorrectly. When the time is 8:00, the value of itIsTimeToGetUp is set to false, which is wrong.

The condition we are using evaluates to true if the hours value is greater than 6 and the minutes value is greater than 29. This means that the condition evaluates to false for any minute value that is less than 29, meaning it is false at 8:00. To fix the problem, we need to develop a slightly more complex test:

Click here to view code image

var itIsTimeToGetUp= (hours>7) || (hours==7 && minutes>29);

I’ve added parentheses to show how the two tests are combined by the || (or) operator. If the value of hours is greater than 7, we don’t care what the value of minutes is. If the hours value is equal to 7, we need to test to see whether the minutes value is greater than 29. If you try the values in the table with the above statement, you will find that it works correctly. This illustrates an important point when designing code intended to perform logic like this. You need to design tests that you can use to ensure that the program will do what you want.

The if construction

Suppose I want to make a program that will display a message telling me whether it’s time to get out of bed. We can use the Boolean value we just created to control the execution of programs by using JavaScript’s if construction. Figure 5-3 shows how an if construction fits together.

Figure 5-3 If construction

The condition controls the execution of the statement. In other words, if the condition is “truthy,” the statement is performed; otherwise, it is not performed.

Click here to view code image

if (itIsTimeToGetUp) alert("It is time to get up!");

The statement above would display an alert if it were time to get up. You can see this in use in the example \Ch05 Making Decisions in Programs\Ch05-01 Alarm Alert, which displays the alert if you visit the page after 07:30 in the morning.

This is the full text of the alarm alert page. Note that the statement that implements the “intelligence” of the program is only one tiny part of the code.

The behavior of the if construction is controlled by the condition. The condition does not have to be a variable; it can also be a logical expression:

Click here to view code image

if ((hours>7) || (hours==7 && minutes>29)) alert("It is time to get up!");

This statement removes the need for the itIsTimeToGetUp variable. However, I quite like using the variable because it helps the user understand what the program is doing.

Adding an else part

Many programs want to perform one action if a condition is true and another action if the condition is false. The if construction can have an else element added, which identifies a statement to be performed if the condition is false. See Figure 5-4.

Figure 5-4 If construction with else

A screenshot shows the source code for alert alarm program. In the line, if( itIsTimeToGetUp) alert (It is time to get up"); controls the alert.

The else part is added onto the end of a conditional statement. If comprises the keyword else followed by the statement to be performed if the condition is false. We could use it to make our alert program display a message when we can stay in bed.

Click here to view code image

if(itIsTimeToGetUp)
    alert("It is time to get up!");
else
    alert("You can stay in bed");

This program displays a different message depending on the time of day that the user runs the program. Note that although I’ve spread the statement over several lines, the content matches the structure in Figure 5-4.

CODE ANALYSIS

If constructions

Question: Must an if construction have an else part?

Answer: No. They are very useful sometimes, but it depends on the problem that the program is trying to solve.

Question: What happens if a condition is never true?

Answer: If a condition is never true, the statement controlled by the condition never gets to run.

Question: Why is the statement underneath the if condition in my example indented by a few spaces?

Answer: This statement doesn’t need to be indented. JavaScript would be able to understand what we want the program to do even if we put everything on one line. The indentation is there to make the program easier to understand. It shows that the statement underneath the if construction is being controlled by the condition above it. Indenting like this is such common practice that you will find the behavior “baked in” to the Visual Studio Code editor. In other words, if you start typing an if construction and press the Enter key at the end of the condition part, Visual Studio Code will automatically indent the next line.

Creating blocks of statements

The if condition controls the execution of a single statement. However, sometimes you might want to perform multiple statements if a condition is true. For example, we might what to play an alarm sound as well as displaying an alert message when it is time to get up. To do this, a program needs to control multiple statements from a single condition. You write code for a task like this by creating a block of statements.

A block of statements is a sequence of JavaScript statements enclosed in a pair of curly braces—the { and } characters. You have already seen blocks of statements in the programs we’ve examined and written. In those programs, the statements in all the functions are enclosed in a block. You can create a block anywhere in a program, and it is equivalent to a single statement.

Click here to view code image

if (itIsTimeToGetUp) {
    alarmAudio.play();
    outputElement.textContent = "It is time to get up!";
}else {
    outputElement.textContent = "You can stay in bed";
}

The code above displays a message and plays an alarm sound. You can find the working program in the example Ch05 Making Decisions in Programs\Ch05-03 Alarm Alert with sound block. This uses the “everything sound” as an alarm, which some might feel a bit harsh, but it certainly wakes me up. Note that in the above code, I’ve used curly braces to enclose the statements for both the if and else parts of the condition, even though there is no need to do this for the else part as it only contains one statement. I do this to make it clear what is going on. It also means that it is easier to add extra statements controlled by the else part because I can just put them inside the block.

Use decisions to make an application

Now that you know how to make decisions in your programs, you can start to make more useful software. Let’s say your next-door neighbor is the owner of a theme park and has a job for you. Some rides at the theme park are restricted to people by age, and he wants to install some computers around his theme park so that people can find out which rides they may go on. He needs some software for the computers, and he’s offering a season pass to the park if you can come up with the goods, which is a very tempting proposition. He provides you with the following information about the rides at his park:

Ride Name

Mininum Age Requirement

Scenic River Cruise

None

Carnival Carousel

At least 3 years old

Jungle Adventure Water Splash

At least 6 years old

Downhill Mountain Run

At least 12 years old

The Regurgitator (a super scary roller coaster)

Must be at least 12 years old and less than 90

You discuss with him the design of the program user interface. The user interface is what people see when they use the program and the steps that they go through when they are using it. In this application, users will specify the ride they want to go on and enter their age. They then click a button and are told whether they can go on that ride (see Figure 5-5).

Figure 5-5 Theme park rides

The page allows the user to enter their age to check if the user is eligible for the particular ride. Here, the user selects ride number as 1, and age as 18. A message is displayed which reads, "you can go to the scenic river cruise."

PROGRAMMER’S POINT

Design the user Interface with the customer

You might think that an interface like this would be simple to design and that the customer will have no strong opinions on how the user interface looks and functions. I’ve found this to be wrong. I’ve had the awful experience of proudly showing my finished solution to a customer only to be told that it was not what they wanted and that it is “hard to use.” I now understand that this was my fault. Rather than showing only my finished design, I should have created the design with the customer. That would have saved me a lot of work.

Build the user interface

The first thing we need to do is create the HTML web page and the style sheet for the application. In Chapter 3, we decided that it was a good idea to separate the style sheet file, which holds the style of the page elements, from the page layout. It is also a good idea to separate the JavaScript program code from the HTML layout. We do this by putting the JavaScript into a file with the language extension “.js.” We can then add an element in the head of the HTML file that specifies this file name:

Click here to view code image

<script src="themepark.js" ></script>

The HTML above is added to the <head> part of an HTML document and includes the contents of the JavaScript file themepark.js in an HTML page. You can see it in use in the HTML below.

A screenshot presents the code for theme park ride selector program. In the head section, the line <link rel equals "stylesheet "href equals "styles.css"> includes the css file, and the line, <script src equals "themepark.js"> </script> includes the JavaScript file. In the body section, the line <ol class equals "menuRideList"> is displayed to start of numbered list of rides.

This is the HTML file for the Theme Park Ride Selector application. It uses some features of HTML that we’ve not seen before. We can create an ordered list of items by using the <ol> tag to enclose some <li> list elements. The browser will automatically number the elements for us. Each element on the page is assigned a class that has a specific style. The settings for each of the styles are in a separate CSS style sheet file called styles.css. A part of this file is given below:

A screenshot displays the css style sheets for the elements in the theme park ride selector program. The line, text-shadow: 3 9x 3px 0 blue, 10px 10px 10px darkblue; adds the shadows to the text. The line, .mentText, .mentRideList, .menuButton, .menuInput, .menu yes, .menu no will be added to all the classes.

The menuHeading class is in the HTML used to format the heading. It uses the Impact font and adds two shadows to the text. The first shadow is blue and close to the text, which provides a 3D effect for each character. The second shadow is more diffuse and darker blue so that it makes the characters appear to stand out from the page. You can see the effect in Figure 5-5. Each shadow is defined by a color value preceded by three values. The first two values give the x and y offsets of the shadow from the text. The third value determines how “diffuse” the shadow is. The first shadow is not diffused at all, whereas the second has a diffusion size of 10px, leading to the text shown earlier in Figure 5-5.

The style sheet also applies some shared settings to all the menu input classes. This means that the font is set once for all those classes, making it easy to change the font if required. It is a good idea to group classes in this way if they all have a set of common characteristics. Remember that classes accumulate setting values, which are then used on the HTML elements that are assigned to that class. So, for example, the menuYes class will bring together the following settings—some from those shared by other menu settings, and some specific to that class:

Click here to view code image

font-family:Arial, Helvetica, sans-serif;
font-size: 2em;

color: green;

Add the code

Now that we have the user interface complete, we need to add the JavaScript that implements the behavior that the application needs. When the user presses the button to check their age, the doCheckAge function runs. This function gets values for the number of the selected ride and the age of the person wishing to use it. The function then tests these values to see whether the combination is valid. The first part of this function works in the same way as the adding machine that we created earlier. It fetches text from the input elements in the HTML and uses the Number function to convert the text into a number.

The screenshot displays the variables from two different program. The line, var rideNo equals Number (rideNoText); gets the ride number that was entered. The line, var ageNo equals Number(ageText); gets the age of the person.

When these statements have completed, the variables rideNo and ageNo contain the number of the ride and the age of the guest. The next thing the function does is get a reference to the paragraph that will be used to display the result. If you look at the HTML for the user interface, you’ll see that this paragraph has the ID menuAnswerPar:

Click here to view code image

var resultElement = document.getElementById("menuAnswerPar");

Now that the program has the input data and somewhere to put the output, it can make decisions about the use of the rides. If the user has selected ride number 1, there are no age restrictions for the Scenic River Cruise, so this code is a single test for a ride number of 1. If the user has selected this ride, we set the style class for the result element to the menuYes class. This has the effect of changing the style of that element so that the text is now green. Then the inner text for the paragraph is set to You can go on the Scenic River Cruise so that this is displayed for the user.

Click here to view code image

if(rideNo==1) {
    // This is the Scenic River Cruise
    // There are no age limits for this ride
    resultElement.className="menuYes";
    resultElement.innerText = "You can go on the Scenic River Cruise";
}

If the user has not selected ride number 1, the program must test to see whether ride number 2 has been picked.

Click here to view code image

if(rideNo==2) {
    // This is the Carnival Carousel
    // riders must be 3 or over
    if(ageNo<3) {
        resultElement.className="menuNo";
        resultElement.innerText = "You are too young for the Carnival Carousel";
    }
    else {
        resultElement.className="menuYes";
        resultElement.innerText = "You can go on the Carnival Carousel";
    }
}

The code above shows how this works. The program works by nesting one conditional statement inside another. Note how I’ve used the layout of the program to make it clear which statements are controlled by which condition.

Now that you have code that works for the Carnival Carousel, you can use it as the basis for the code that handles some of the other rides. To make the program work correctly for the Jungle Adventure Water Splash, you need to check for a different ride number and confirm or reject the user based on a different age value. Remember that for this ride, a visitor must be at least six years old.

Click here to view code image

if(rideNo==3) {
    // This is the Jungle Adventure Water Splash
    if(ageNo<6) {
        resultElement.className="menuNo";
        resultElement.innerText =
           "You are too young for Jungle Adventure Water Splash";
    }
    else {
        resultElement.className="menuYes";
        resultElement.innerText = "You can go on Jungle Adventure Water Splash";
    }
}

You can implement the Downhill Mountain Run very easily by using the same pattern as for the previous two rides. But the final ride, the Regurgitator, is the most difficult. The ride is so extreme that the owner of the theme park is concerned for the health of older people who ride it and has added a maximum age restriction as well as a minimum age. The program must test for users who are older than 90 as well as those who are younger than 12. We must design a sequence of conditions to deal with this situation.

The code that deals with the Regurgitator is the most complex piece of the program that we’ve had to write so far. To make sense of how it needs to work, you need to know more about the way that if constructions are used in programs. Consider the following code:

Click here to view code image

if(rideNo==5) {
    // This is the Regurgitator

The condition is true when the user has selected ride number 3, and all the statements we add to the block of code controlled by this condition will run only if the selected ride is the Regurgitator. In other words, there is no need for any statement in that block to ask the question “Is the selected ride the Regurgitator?” because the statements are run only if this is the case. The decisions leading up to a statement in a program determine the context in which that statement will run. I like to add comments to clarify the context:

Click here to view code image

if(rideNo==5) {
    // This is the Regurgitator
    if(ageNo<12) {
        resultElement.className="menuNo";
        resultElement.innerText = "You are too young for the Regurgitator";
    }
    else {
        // get here if the age is 12 or above
        if(ageNo>90) {
            resultElement.className="menuNo";
            resultElement.innerText = "You are too old for the Regurgitator";
        }
        else {
            resultElement.className="menuYes";
            resultElement.innerText = "You can go on the Regurgitator";
        }
    }
}

These comments make the program slightly longer, but they also make it a lot clearer. This code is the complete construction that deals with the Regurgitator. The best way to work out what it does is to work through each statement in turn with a value for the user’s age. You can find all the sample code in the folder Ch05 Making Decisions in Programs\Ch05-04 Theme Park.

Using the switch construction

The program code for the ride selector is a sequence of if constructions controlled by the value of rideNo. This pattern appears frequently in programs, so JavaScript contains an additional construction to make it slightly easier. This is something we’ve not seen before. Up until now, everything we have learned is about making something possible. However, the switch construction is all about making something easier. Programs can use a switch to select different behaviors based on the value in a single control variable. Take a look at this code, which implements the Theme Park Ride Selector.

Click here to view code image

switch(rideNo)
{
    case 1:
    // This is the Scenic River Cruise
    // There are no age limits for this ride
    resultElement.className = "menuYes";
    resultElement.innerText = "You can go on the Scenic River Cruise";
    break;

    case 2:
    // This is the Carnival Carousel
    // .. statements for Carnival Carousel go here
    break;

    case 3:
    // This is the Jungle Adventure Water Splash
    // .. statements for Jungle Adventure Water Splash go here
    break;

    case 4:
    // This is the Downhill Mountain Run
    // .. statements for Downhill Mountain Run go here
    break;

    case 5:
    // This is the Regurgitator
    // .. statements for the Regurgitator go here
}

The code above shows how the switch would be used. The value in rideNo is used as the control value for the switch, and the program will select the case that matches the control value. You can put as many statements as you like in a particular case, but you must make sure that the last statement in the case is the break keyword, which ends the execution of the code for that case. You can find my switch-powered solution for the Theme Park ride selector in the Ch05 Making Decisions in Programs\Ch05-05 Switch Theme Park Ride Selector folder.

You can use the switch statement with strings and integer values, which can be a convenient way of selecting an option. A switch construction can have a default selector, which is obeyed if none of the cases match the control value. You can also use multiple case elements to select a particular behavior. The switch below is controlled by a variable called commandName. The commands Delete, Del, and Erase all result in the erase behavior being selected:

Click here to view code image

var commandName ;

switch(commandName)
{
    case "Delete":
    case "Del":
    case "Erase":
        // Erase behavior goes here
        break;

    case "Print":
    case "Pr":
    case "Output":
        // Print behavior goes here
        break;

    default:
        // Invalid command behavior goes here
        break;
}

WHAT COULD GO WRONG

Missing breaks in switches can cause mayhem

Click here to view code image

switch(rideNo)
{
    case 1:
    // This is the Scenic River Cruise
    // There are no age limits for this ride
    resultElement.className = "menuYes";
    resultElement.innerText = "You can go on the Scenic River Cruise";

    case 2:
    // This is the Carnival Carousel
    if (ageNo < 3) {
        resultElement.className = "menuNo";
        resultElement.innerText = "You are too young for the Carnival Carousel";
    }
    else {
        resultElement.className = "menuYes";
        resultElement.innerText = "You can go on the Carnival Carousel";
    }
    break;
}

The code above is part of my switch-controlled version of the Theme Park ride selector. It has a dangerous bug in it. The bug will not cause JavaScript to crash, but it will cause the program to do the wrong thing. The bug is caused by a missing break keyword between case 1 and case 2. When the user selects ride number 1, the program will perform the statements for case 1 and then go straight through and perform the statements for case 2. This means that if the user selects the Scenic River Cruise (option 1), the program will behave as if the Carnival Carousel (option 2) was selected. Bugs like this that cause a program to “mostly work” are particularly dangerous, and you should make sure to test for every input to make sure that you have no missing breaks in your switches.

MAKE SOMETHING HAPPEN

Improve the ride selector

You can use the application in Ch05 Making Decisions in Programs\Ch05-04 Theme Park as the starting point for a really good ride selector program—but it is not perfect. It would benefit from some testing of the input values to prevent the user from entering invalid ride numbers or age values. You could even design custom graphics for each ride and then display them when the ride is selected. You could even add suitable sound effects for each ride, too.

Fortune Teller

The Math.random function can be used in if constructions to make programs that perform in a way that appears random.

Click here to view code image

var resultString = "You will meet a ";

if(Math.random()>0.5)
  resultString = resultString+"tall ";
else
  resultString = resultString+"short ";

if(Math.random()>0.5)
  resultString = resultString+"blonde ";
else
  resultString = resultString+"dark ";

resultString = resultString + "stranger.";

The if constructions test the value produced by a call to the Math.random function. This produces a value in the range 0 to 1. If the value is less than 0.5, the program selects one option; otherwise, another option is picked. This is repeated to produce a random seeming program. You can build on this sequence of such conditions to make a fun fortune teller program. You could also create some graphical images to go along with the program predictions.

What you have learned

This chapter has introduced you to the use of Boolean values in programs and showed you how to make code that can take decisions. Here are the major points we have covered:

Boolean data has one of only two possible values—true or false. JavaScript contains the keywords true and false that can be used to represent these values in programs.

JavaScript can regard variables of other types in terms of their “truthy” or “falsy” nature. Any numeric value other than 0 is regarded as true. Any string other than an empty string is regarded as true. The value that represents Not a Number (NaN) is regarded as false, but the value that represents Inifinity is regarded as true.

The JavaScript function Boolean can be used to convert a variable of any type into the Boolean value true or false, according to the ways of “truthy” and “falsy.”

Programs can generate Boolean values by using comparison operators such as < (less than) between values of other types. Care should be exercised when comparing floating point values (numbers with a fractional part) for equality because they might not be held accurately.

JavaScript provides two ways to test if things are the same. The equality comparison operator (==) will promote values before comparing them. Comparing the values true and 1 for equality would give a true result because the logical value true would be promoted to 1 before the comparison. The identity comparison operator (===) will always return false when comparing values of different types, so comparing true and 1 for identity would return false.

JavaScript also provides Boolean operators such as && (and) that can be used between Boolean values.

The if construction is used in programs to select statements based on Boolean expression used as a condition. The if construction can have an else part, which specifies a statement to be performed if the condition is false. Conditional statements can be nested.

JavaScript statements can be enclosed in curly braces ({ and })to create blocks that can be controlled by a single condition in an if construction.

It is possible to store the JavaScript component of an application in a separate code file that is included in an HTML page.

The switch construction is an easier way to create code that selects a behavior based on the content of a single control variable.

Here are some questions that you might like to ponder about making decisions in programs:

Can a program test two boolean values to see if they are equal?

Yes, it can. The equality operator (==) will work between two values that are either true or false.

Why does JavaScript provide equality and identity logical operators?

The identity operator (===) can be said to be “stricter” than the equality operator (==) because attempts to compare values of different types (for example compare a number with a Boolean value) will always return false. This is why some programmers (including me) use identity (===) in preference to equality (==).

Can JavaScript regard any value in terms of “truthy” and “falsy”?

Yes. Essentially, if there is something there (a value other than zero or a non-empty string) then this will be regarded as true. Otherwise, it will be false.

Must every if construction have an else part?

No. If an else is present, it will “bind” to the nearest if construction in the program. If you write a program in which only some conditions have an else part, you need to make sure that an else binds to the correct if.

Is there a limit to how many if conditions you can nest inside each other?

No. JavaScript will be quite happy to let you put 100 if statements in a row (although you would have a problem editing them). If you find yourself doing this, you might want to step back from the problem a bit and see if there is a better way of attacking the problem.

How long can a block be?

A block of code can be very long indeed. You could control 1,000 lines of JavaScript with a single if condition. However, very long blocks can make code hard to understand. If you want to control a large amount of code with a condition, you should put the code into a function. We will learn about functions in Chapter 8.

Does the use of Boolean values mean that a program will always do the same thing given the same data inputs?

It is very important that, given the same inputs, the computer does the same thing each time. If the computer starts to behave inconsistently, this makes it much less useful. When we want random behavior from a computer (for example, when writing a fortune teller program), we have to obtain values that are explicitly random and make decisions based on those. Nobody wants a “moody” computer that changes its mind (although, of course, it might be fun to try to program one using random numbers).

Will the computer always do the right thing when we write programs that make decisions?

It would be great if we could guarantee that the computer will always do the right thing. However, the computer is only ever as good as the program it is running. If something happens that the program was not expecting, it might respond incorrectly. For example, if a program was working out cooking time for a bowl of soup, and the user entered 10 servings rather than 1, the program would set the cooking time to be far too long (and probably burn down the kitchen in the process).

In that situation, you can blame the user (because they input the wrong data), but there should probably also be a test in the program that checks to see if the value entered is sensible. If the cooker can’t hold more than 3 servings, it would seem sensible to perform a test that limits the input to 3.

This part of a program is called “input validation,” and it is a very important that programs do this. When you write a program, you need to “second guess” what the user might do and create decisions that make your program behave sensibly in each situation.

6
Repeating actions in programs

What you will learn

In the last chapter, you learned how a program can make decisions and change its behavior according to the data that it is given. In this chapter, you are going to discover how to make a program repeat a sequence of actions using the JavaScript loop constructions. Along the way, we’re going to explore some new features of HTML and JavaScript. We are also going to discover some ways that programs can go wrong and how good design can reduce the chances of a program failing.

App development

Investigate list elements

Building web pages from code

More multiplication table fun

What you have learned

App development

Our starting point is the Theme Park Ride Selector program developed in Chapter 5. This program uses conditional (if) constructions to display whether a rider can go on their selected ride.

Figure 6-1 shows the solution in use. The rider entered their age as 18 and selected ride number 1, the Scenic River Cruise, which they can go on. The program works, but the owner of the theme park wants changes. She wants to remove the need for the ride selection and have the program display the ride names in red or green to indicate which ones can be ridden for a given age. She has created a new design and wants you to rewrite the application to match.

Figure 6-1 Theme Park Ride Selector

The page allows the user to enter their age to check if the user is eligible for the particular ride. Here, the user selects ride number as 1, and age as 18. A message is displayed which reads, "you can go to the scenic river cruise."

Figure 6-2 shows how the updated application will work. The rides that are available to an 8-year-old are shown in green. The first thing we need to do is remove the ride numbers from the ride display. The previous application used a numbered list because the rider had entered their chosen ride number. However, the new application doesn’t need ride numbers.

Click here to view code image

<ul class="menuRideList" id="rideList">
    <li id="scenicRiver">Scenic River Cruise</li>
    <li id="carnivalCarousel">Carnival Carousel</li>
    <li id="jungleAdventure">Jungle Adventure Water Splash</li>
    <li id="downhillMountain">Downhill Mountain Run</li>
    <li id="regurgitator">The Regurgitator</li>
</ul>

Figure 6-2 Proposed New Design

The page lists the rides that are available. It allows the user to enter their age to check if the user is eligible for a ride. Here, the user enters the age as 8. The 'check your rides' button is displayed at the bottom. The first three rides are displayed in green to indicate that the user is eligible for those rides. The last two rides are displayed in red to indicate that the user is not eligible.

This is the HTML that we will use to display the names of the rides in the updated application. It uses an unordered list element— <ul>—that holds a collection of list elements (<li>) for rides. These are not displayed with numbers. Now we need to modify the program in the JavaScript code that controls the behavior of the application. The program will get the age of the rider and then use it to indicate whether the rider can go on each ride.

The screenshot shows a part of a program to check the age of the rider and to display the result. The line, var jungleAdventureElement equals document.getElementById("jungleAdventure"); gets the reference to the ride name display. The line, if (ageNo less than 6) { tests the age value. The line, jungleAdventureElement.className equals "menuNo"; is displayed to change the color to red if the ride can't be used. The line, } else { performed if the ride can be used. The line, jungleAdventureElement.ClassName equals "menuYes"; is displayed to turn the color to green if the ride can be used.

This code shows how the program displays the results for the Jungle Adventure ride. It follows a pattern that we have seen many times before:

Get a reference to the document element that will display the result for the rider to see.

Update a property of this document element to show the result.

The code above sets a variable called jungleAdventureElement to refer to the element holding the text being displayed for the Jungle Adventure ride. (This is the list item with the ID jungleAdventure.) It then uses a conditional statement controlled by the value in ageNo to update the className property of jungleAdventureElement to an appropriate style. The ageNo variable contains the age of the rider.

When the program runs, the className property of jungleAdventureElement is set to menuNo if the value in ageNo is less than 6. If the value in ageNo is greater than or equal to 6, the else part of the conditional statement is performed, and the className property of the element is set to menuYes. The className property of an element gives the style sheet class to be used to format this element. These two classes are defined in the styles.css file for this application, and they look like this:

.menuYes {
    color: green;
}

.menuNo{
    color: red;
}

This combination of JavaScript and style sheet will cause the text for the Jungle Adventure to change to red if the age of the ride user is less than 6 and to green for any other age. We must implement this construction for all the other rides in the theme park. A friend of ours is looking for some free access to the Theme Park, so we decide to subcontract the work to him. He is an experienced programmer (or at least he has read a couple more books than we have). He does the work, gets his Theme Park tickets, and hands over the finished program. The new program seems to work well, and the owner of the theme park is pleased with it at first. However, after a while, he starts to get complaints from riders about incorrect displays for the Downhill Mountain Run ride. We need to find out what has gone wrong.

PROGRAMMER’S POINT

Always respond constructively to fault reports

I’ve had my share of bugs over the years. I learned quickly that customers appreciate a positive response to their fault reports. It is important to remember that when you are fixing a fault, your loyalty is to solving the problem, not finding out who caused it. I never made a fuss when a bug turned out not to be my fault, and I always accepted responsibility when it was. By being constructive in my approach to fault reports, I could turn a negative into a positive, so that my customers would end up praising my fault-fixing skills rather moaning about my buggy code.

CODE ANALYSIS

Fixing faults

Programs contain bugs because they are created by fallible humans. We get a bug when, for whatever reason, a program does something that it should not. A bug becomes a fault when it affects the user in some way. It seems that there is a bug in the ride program that is causing the faulty display. Let’s open the program in the Ch06 Repeating actions\Ch06-01 Broken Ride Selector folder and take a look.

Question: What age values don’t work?

Answer: We’ve been told that the Downhill Mountain Run ride display is not working properly. Only riders who are 12 years or over can use this ride. Let’s start with an age that is less than 12:

The screenshot lists the rides that are available. It allows the user to enter their age to check if the user is eligible for a ride. Here, the user enters the age as 8. The 'check your rides' button is displayed at the bottom. The first three rides are displayed in green to indicate that the user is eligible for those rides. The last two rides are displayed in red to indicate that the user is not eligible.

This test shows that the program is working correctly for 8-year-old riders. They should not be allowed on the Downhill Mountain Run or the Regurgitator. Let’s try 12—an age that should work.

The screenshot lists the rides that are available. It allows the user to enter their age to check if the user is eligible for a ride. Here, the user enters the age as 12. The 'check your rides' button is displayed at the bottom. The ride 'Downhill mountain run' is displayed in red color, while the other rides are displayed in green.

Aha! The bug is exposed. The Downhill Mountain Run is displayed in red, which is incorrect. A rider who is 12 years old should be allowed to go on this ride.

Question: What could cause the error?

Answer: Now we can see the bug we can investigate the cause. Use Visual Studio Code to open the themepark.js program file in the example folder and investigate the code. The part that you need to find is the part that handles the Downhill Mountain Run ride. There is a bug here. Can you see it?

Click here to view code image

var downhillMountainElement= document.getElementById("downhillMountain");
if (ageNo < 12) {
    downhillMountainElement.className = "menuNo";
} else {
    jungleAdventureElement.className = "menuYes";
}

The program is supposed to set the Downhill Mountain element to red if the age is less than 12; otherwise, it should set the element to green. The logic is the same as that used for the Jungle Adventure ride, but this code is broken. Have you spotted the error yet?

Click here to view code image

var downhillMountainElement= document.getElementById("downhillMountain");
if (ageNo < 12) {
    downhillMountainElement.className = "menuNo";
} else {
    jungleAdventureElement.className = "menuYes";
}

The error is in the else part. I’ve highlighted it above. Rather than setting the className on the downhillMountainElement, it instead works on the jungleAdventureElement. The program is deciding correctly that the rider can go on the Downhill Mountain Run ride, but then it is displaying the result on the wrong element.

Question: How do we fix the bug?

Answer: This bug is easy to fix. We just need to change it so that the correct element is updated when the rider can go on the ride.

Click here to view code image

var downhillMountainElement= document.getElementById("downhillMountain");
if (ageNo < 12) {
    downhillMountainElement.className = "menuNo";
} else {
    downhillMountainElement.className = "menuYes";
}

Question: How would you make a mistake like this?

Answer: It seems very strange to type a completely wrong name. But this kind of bug is quite likely. Consider how the code would be written. Our programming friend created the code for the Jungle Adventure ride and then copied it for the Downhill Mountain Run ride. He should have changed all the identifiers, but he missed one out and caused the bug.

Question: How do we prevent mistakes like this?

Answer: The primary cause of the fault was a lack of proper testing. If the program had been properly tested, the fault would have shown up. However, the practice of using block copy when writing the code made the bug possible. We should try to write our solutions in a way that reduces the number of ways they could go wrong. This includes not using block copy to repeat sections.

The importance of well-designed code

A bridge made of random pieces of wood nailed together that shudders and creaks as you cross it is probably not built to a particularly good design. You can consider software in design terms, too. The theme park ride application we have created is like a badly made bridge. It works, but the internal structure is not good. As we have seen above, using multiple copies of the same if construction makes mistakes likely when writing the code. There is also another possible source of error. The names of the rides are held in the HTML file, but the age limits for the riders are held in the JavaScript file. If we want to add more rides or adjust the age limits for the rides, we must edit both and make sure that their contents line up. Any mistakes will show up as more bugs.

PROGRAMMER’S POINT

Design is important

You might think that worrying about the internal design of a program is a waste of time. If the program works, why do we need to care about how it fits together? However, it is important that you always strive to make your code well designed. If you are still not convinced, consider the implications of a bug in the Theme Park Ride Selector that allowed a three-year-old to go on the Regurgitator ride. The child might be injured, and the Theme Park owner would be in a lot of trouble. An investigation might conclude that we were at fault for not using best practice when creating the code.

When we make a solution, we should try to make it easy to understand how it works. Bugs can appear when one programmer modifies the work of another and doesn’t fully understand how the original code worked. The easier that program is to understand and the smaller the number of required changes, the lower the likelihood of bugs being introduced. We will look at design techniques throughout the rest of this book.

Adding data attributes to HTML elements

We can start to improve the structure of our application by putting all the data that controls it in the same place. This will remove one possible cause of errors. We are going to do this by putting the age limits inside the elements that display the ride information in a web page. This is a powerful feature of HTML and JavaScript that we will use a lot in later programs. The feature we are going to use is called a data attribute.

We have seen that an HTML element can contain attributes that modify it in some way. For example, to display red text, I add a style attribute to a paragraph to select red.

Click here to view code image

<p style="color:red">This is a red paragraph.</p>

An attribute is something that modifies an element. Each HTML element uses a particular set of attributes: A p element has a style attribute that sets the text style (as we saw above), and an image element has a src attribute that specifies the source file containing an image (as we saw when we displayed images). An element can also contain data attributes.

Click here to view code image

<ul class="menuRideList" id="rideList">
   <li data-MinAge="0" data-MaxAge="120" id="scenicRiver">Scenic River Cruise</li>
   <li data-MinAge="3" data-MaxAge="120" id="carnivalCarousel">Carnival Carousel</li>
   <li data-MinAge="6" data-MaxAge="120"
       id="jungleAdventure">Jungle Adventure Water Splash</li>
   <li data-MinAge="12" data-MaxAge="120"
       id="downhillMountain">Downhill Mountain Run</li>
   <li data-MinAge="12" data-MaxAge="90" id="regurgitator">The Regurgitator</li>
</ul>

The HTML above is like the earlier list of theme park rides, but each of the list items now has a data-MinAge and a data-MaxAge attribute. These give the age limits for each of the rides. This information about rides and ages is now all held in one place. The JavaScript program can use the getAttribute method provided by an element to read the contents of a data attribute.

The screenshot shows the source code to display the working process of attribute in Carnival Carousel ride. The line, var carnivalMinAgeText equals carnivalCarouselElement.getAttribute("data-MinAge"); reads the minimum age attribute. The line, var carnivalMaxAgeText equals carnivalCarouselElement.getAttribute("data-MaxAge"); reads the max age attribute.

The code above shows how this would work for the Carnival Carousel ride. Note that the value of an attribute is a string of text, so the Number function is used to convert the text into a numeric value. Once the program has the maximum and minimum ages, it can then update the display to indicate whether the rider can go on the ride.

Click here to view code image

if(ageNo<carnivalMinAgeNo){
    carnivalCarouselElement.className="menuNo";
} else {
    if(ageNo>carinvalMaxAgeNo){
        carnivalCarouselElement.className="menuNo";
    } else {
        carnivalCarouselElement.className="menuYes";
    }
}

CODE ANALYSIS

Data attributes

You may have some questions about data attributes. Let’s see if we can answer them by looking at some code. Start with the sample application in the Ch06 Repeating actions\Ch06-03 Data Ride Selector example folder. Open this in your browser. Enter an age of 2 and click Check Your Rides. You will see the display below.

The page lists the rides that are available. It allows the user to enter their age to check if the user is eligible for a ride. Here, the age is mentioned as 8. The ride 'scenic river cruise' is displayed in green, while the 'carnival carousal' is displayed in red.

Question: Why are the two ride names shown in different colors?

Answer: The Scenic River Cruise text is green because the minimum age attribute for Scenic River Cruise list item is 0, and an age of 2 is greater than 0. The Carnival Carousel text is red because an age of 2 is less than the minimum age for that ride, which is 3.

Question: What is the upper limit for the age of the Carnival Carousel ride?

Answer: We can answer this question by looking at the data attributes on the Carnival Carousel list element in the HTML document. Press F12 to open the Developer View. Now type in the following JavaScript statement:

Click here to view code image

> var carnivalCarouselElement = document.getElementById("carnivalCarousel");

This statement creates a variable called carnivalCruiseElement that refers to the Carnival Carousel list element in the web page. Press Enter to run it.

Click here to view code image

> var carnivalCarouselElement = document.getElementById("carnivalCarousel");
<- undefined

When you press Enter, the variable is created, and the statement that created the variable returns a value of undefined. Now we can use the getAttribute method to get data out of this element. Enter the following statement:

Click here to view code image

> carnivalCarouselElement.getAttribute("data-MaxAge");
<- "120"

This returns the value 120, which is the contents of the data-MaxAge attribute in the Carnival Carousel element. This means that the maximum age for that ride is set to 120 years. You can use the same method to read the minimum age value.

Click here to view code image

> carnivalCarouselElement.getAttribute("data-MinAge");
<- "3"

Question: What happens if we ask getAttribute to find a data attribute that doesn’t exist?

Answer: Let’s try it. Enter the statement below, which looks for a data attribute called data-SillyAge:

Click here to view code image

> carnivalCarouselElement.getAttribute("data-SillyAge");
<- null

This call of getAttribute returns null, which is how JavaScript indicates that a reference value doesn’t refer to anything. In other words, the getAttribute method couldn’t find anything, and so it returned a value that indicates that nothing was found. We could use an if construction to test for a value of null, so our program could do something sensible if a data attribute is not found.

Question: Can I set the value of a data attribute in an element?

Answer: Yes, you can. There is a method called setAttribute that is provided with the name of a data attribute and the value to be set in the attribute. It sets the data attribute to that value. Enter the following statement to set the maximum age for the ride to 99.

Click here to view code image

> carnivalCarouselElement.setAttribute("data-maxAge", "99");
<- undefined

We can test this by reading back the value of the maximum age:

Click here to view code image

> carnivalCarouselElement.getAttribute("data-MaxAge");
<- "99"

Question: Can a program create new data attributes on an element?

Answer: Yes. This can be used to “bind” data to elements. The setAttribute method will create a new attribute if the one being set does not exist. Try the following statements, which create a test data attribute called data-test on the Carnival Carousal element:

Click here to view code image

> carnivalCarouselElement.setAttribute("data-test", "test string");
<- null
> carnivalCarouselElement.getAttribute("data-test");
<- "test string"

Question: Does the name of a data attribute have to start with the characters “data-“?

Answer: JavaScript does not enforce this rule, but it is a very sensible convention so that someone reading the code does not mistake a data attribute for a “normal” attribute of that element.

Question: Can my program add data attributes to any HTML element?

Answer: Yes, it can. This is a good way to store data values inside your web page.

Using an unordered list as a container

The code in the Ch06 Repeating actions\Ch06-03 Data Ride Selector example folder only handles two rides. The reason for this is that I just didn’t feel like copying the Carnival Carousel code for the other rides. It seemed like too much hard work, and I was concerned I might make a mistake. It turns out that there is a much easier way of handling all the other rides that uses a loop to work through the list of rides.

Click here to view code image

<ul class="menuRideList" id="rideList">
    <li data-MinAge="0" data-MaxAge="120">Scenic River Cruise</li>
    <li data-MinAge="3" data-MaxAge="120">Carnival Carousel</li>
    <li data-MinAge="6" data-MaxAge="120">Jungle Adventure Water Splash</li>
    <li data-MinAge="12" data-MaxAge="120">Downhill Mountain Run</li>
    <li data-MinAge="12" data-MaxAge="70">The Regurgitator</li>
</ul>

The HTML above shows the list of rides in the Theme Park as they are displayed. Each of the rides is described by a list item (<li>) element and all the lists are enclosed inside an unnumbered list (<ul>) element. The <ul> element is a container element that holds other elements. In this case, the list contains five list items. These list items are called the children of their container elements. HTML elements provide methods that can be used to access the children of an element. Let’s investigate.

MAKE SOMETHING HAPPEN

Investigate list elements

Start by opening the application in the Ch06 Repeating actions\Ch06-04 Theme Park Ride For Loop folder in the example code. This is a fully working ride selector that uses a for loop. We’ll discover how the for loop works later in this section. For now, we are going to take a look at the list container. Open the Developer View by pressing the function key F12. Now we can start typing commands into the JavaScript command prompt. The first thing we are going to do is get a reference to the list that holds the ride names:

Click here to view code image

> var rideListElement= document.getElementById("rideList");
<- undefined

When you press Enter, the JavaScript console returns the result as undefined because, as we know, the process of creating a variable does not return a value. However, the variable rideListElement now refers to the list of rides. To prove this, just type the name rideListElement, and the Developer View will show you the HTML in the element it refers to:

When you press Enter this time, the JavaScript console displays the element. Click the little right-pointing arrow to expand the display.

The snapshot shows the expanded elements under the line that reads "<ul class equals "menuRideList" id equals "ridelist"> ellipsis </ul>.

The list has five children, which are the list items. These children are held in a property of the list, which is called children. We can use an index to specify which of the children we want to look at. The index is expressed as a number enclosed in square brackets ([]): Let’s have a look at the element at the start of the list. Type in the statement below.

Click here to view code image

> rideListElement.children[0]

Note that this is the element with an index of 0. When counting items in a container, JavaScript starts counting at zero, not one. When you press Enter, the list item for the Scenic River Cruise is displayed.

Click here to view code image

<- <li data-MinAge="0" data-MaxAge="120">Scenic River Cruise</li>

You can use this technique to obtain any of the items in the list. The statement below will view the list item for the Regurgitator. I tried it with a different number:

Click here to view code image

> rideListElement.children[4]
<- <li data-MinAge="12" data-MaxAge="70">The Regurgitator</li>

Remember that because JavaScript counts elements from 0, the final element in a list containing four elements will have an index of 4. You might be wondering what will happen if you try to access an element that isn’t there. Try this:

Click here to view code image

> rideListElement.children[5]

There is not a fifth element in the list (although the film The Fifth Element is a classic). The result of trying to find a non-existent element is the undefined value:

<- undefined

We can find out how many children there are by using the length property of children. Try this statement to see how it works:

Click here to view code image

> rideListElement.children.length

There are five children, and so the length property will be 5:

<- 5

Leave your browser open for now, as we will be using it to investigate loops a little later.

The JavaScript for loop

Now that we know how to get hold of the list items in the ride list, the next thing we need to be able to do is use the items in our application. What we need is language construction that will loop round a block of code and count each time around the loop. It turns out that JavaScript has just the thing. It is called the for loop. Figure 6-3 shows the elements of a JavaScript for loop.

Figure 6-3 For loop

setup The setup (sometimes called initialization) element is performed once when the for loop is started.

test The test element is performed before every pass through the code in the loop. If the test has a JavaScript “truthy” value of true, the loop will continue. If the test has a “truthy” value of false, the loop will end, and the program will continue at the statement after the for loop.

update The update element is performed after each execution of the loop.

statement The statement is a JavaScript statement that is to be repeated by the for loop. This can be a block of statements enclosed in curly braces if you want the loop to perform more than one statement.

A for loop is usually used with a control variable. This variable counts the number of times the loop has been performed. The setup element puts a starting value in the control variable. The test element tests the value of the control variable and will stop the loop when the control variable reaches a particular value. The update element increases the value of the control variable.

Figure 6-4 shows a complete for loop. This causes the loop statement to be performed 10 times. Let’s take a proper look at it.

Figure 6-4 For loop counter

The 'for loop' counter is as follows. For left parenthesis i equals 0 (setup); i less than 10 (test); i equals i plus 1 (test) right parenthesis console .log left parenthesis i right parenthesis (statement);.

CODE ANALYSIS

The for loop

We can use the Developer View in the browser to investigate what a for loop does. Open the application in the Ch06 Repeating actions\Ch06-04 Theme Park Ride For Loop folder (if you haven’t already) and then open the Developer View by pressing F12.

Question: What does the for loop we have created actually do?

Answer: We can start by typing in the JavaScript that you have just seen in Figure 6-4:

Click here to view code image

> for(let i=0;i<10;i=i+1)console.log(i);

You know (because I’ve told you) that this should repeat the statement console.log(i) 10 times—whatever that does. Press Enter to see what happens.

Click here to view code image

> for(let i=0;i<10;i=i+1)console.log(i);
0
1
2
3
4
5
6
7
8
9
<- undefined

The console.log statement is a useful tool for debugging a program. It logs values on the Developer View console. In this case, it is logging the value of i each time it is called. The value of i starts at 0. Each time around the loop, the value in i is increased by 1. The loop also tests the value in i using the condition i<10. When i reaches the value 10, this condition is no longer true (the value 10 is not less than 10) and so the loop stops.

Question: Why does the for loop display undefined at the end.

Answer: The for loop does not display this message. This message is displayed because the console always displays the value of a statement. A for loop construction does not generate a result in the same way that creating a variable using var does not generate a result. In both cases, the value undefined is displayed by the console.

Question: Can I use a for loop to control lots of statements?

Yes. A for loop can control a block of statements enclosed in curly braces ({}) in the same way as an if construction.

Question: What does the word let mean in front of the declaration of i?

Answer: Up until now, we have created our variables using the JavaScript keyword var. However, we can also create a variable by using the keyword let. Variables created using var can be used anywhere in the program after they have been declared. Variables created using let are only useable in the block where they were declared. The value in i is only used inside the statement controlled by the for loop, so it should only exist inside that for loop. To prove that this has happened, enter the following statement to try and look at the value in i:

> i;

This variable no longer exists because it was deleted when the for loop was completed.

Click here to view code image

<-Uncaught ReferenceError: i is not defined at <anonymous>:1:1

Question: Why is it a good idea for variables to disappear like this?

Answer: This is another piece of good design. I tend to use a variable called i for counting. Other programmers working on this code might decide to use a variable called i for something else. I don’t want these two variables to clash, so I make sure that my version of the variable only exists when I use it.

Question: What happens if JavaScript is given a loop that will never run?

Click here to view code image

> for(let i=0;i>10;i=i+1)console.log(i);

Answer: This loop is silly. The loop sets i to 0 and then continues while the value of i is greater than 10. Because the value of i is not greater than 10, the loop will never be performed. If you run this code, you will discover that it does not produce any output.

> undefined

Question: What happens if I put in a loop that will never end? (Please don’t actually run this statement before reading the answer.)

Click here to view code image

> for(let i=0;i<10;i=i-1)console.log(i);

Answer: This loop is also silly. Each time around the loop, the value of i is reduced by 1 rather than increased by 1. This means that the value of i will never reach 10, so the loop will run forever. If you run this statement (and I don’t advise it), you will notice that the console will be filled with ever-decreasing numbers, the fan on your computer will come on, and your browser will become strangely unresponsive as it tries to run this loop as quickly as possible. The only way to stop this that always works is to close the browser tab holding the program. Sometimes when you visit a web page, you find that your browser gets “stuck.” Now you know one way that it can happen.

Now that we know about for loops, we can write the code for the Theme Park Ride Selector.

I love this code. I really like how it works. You should spend some time looking through it to make sure that you understand how it fits together. To appreciate how well designed it is, consider what changes you would have to make to the program if the theme park added another ride. The wonderful answer is that you would not have to change this code at all. You would just have to add another item to the list in the HTML file. You also don’t have to change the program code if the age rating on one of the rides is changed. You just change the data in the HTML file and the program keeps going. The example solution in the folder \Ch06 Repeating actions\Ch06-05 Lots of Theme Park Rides has lots of additional rides, but the JavaScript program code is the same.

PROGRAMMER’S POINT

Great programmers are “constructively lazy”

You can spot a great programmer by the way that they use their skills to avoid hard work. I call this “constructive laziness.” If I find myself having to write lots of code or worrying about synchronizing different parts of a solution, I will try to find a way of using a loop and bringing things together into one place.

Work through collections using for-of

We’ve seen how we can use a for loop to count through a range of values. We might find a use for this a bit later in the chapter, but we can also use a new form of the for loop to directly work through the items in a container. The for – of loop was not added to make something possible; we already know how to solve the problem. It was added to make something easier.

The screenshot displays the 'for-of' loop in the theme park ride selector program. In the line, For ( let rideElement of rideListElement.children), the 'rideElement 'is set to the value of each element in the collection. The term 'children' is a collection that is being worked through.

The loop above shows how it would be used. The loop will be performed for each of the children of the ride list. Each time round the loop the value of rideElement is set to the next child. There is no need to create a control variable and the code is much simpler. You can see a for-of loop in action in the example in Ch06 Repeating actions\Ch06-06 For of loop.

Building web pages from code

The Theme Park Ride Selector makes good use of the way that a JavaScript program can interact with the elements in a web page. Now let’s take this technique even further and find out how a JavaScript program can create new elements on the page when it runs. Then we can make web pages that construct themselves when they are loaded. For example, perhaps we might be asked to create a program to help people learn their multiplication tables. Users enter a number and get a display of the multiplication table for that number.

Figure 6-5 shows how the program is used. The user enters the number of the multiplication table that they want, and the program displays it. This program looks a lot like the Theme Park Ride Selector that we have already created.

Figure 6-5 Multiplication tables

The page allows the user to enter the number for which the multiplication table is needed. Here, the value 2 is entered. The page lists the multiplication table for 2.

We could use a 12-element list to hold the results and then update the text in the list items with the multiplication table that the user has requested in the same way that we update the color of each ride entry. However, that would mean we would have to type in a 12-element list, and that sounds like a bit too much work to me. So let’s start with an empty HTML document and then write some JavaScript to fill in the multiplication table results by creating list items.

A screenshot presents the source code for the multiplication table program. In the line, <ul class equals "menumultiplicationTableList" id equals "multiplicationTableList"> the class is an empty list to hold the multiplication table results. The line min equals "2"max equals "12" </p> is the input for the required multiplication table. The line <button class equals "menuButton"onclick equals "doMultiplicationTables()"> make the multiplication table </button> is displayed to produce the multiplication table when the user clicks on this button.

This is the HTML page for the multiplication table application. Note that in the middle there is an empty list with the ID multiplicationTableList. This is going to hold the multiplication table that the program will generate. The user will press the Make the multiplication table button, which will call the JavaScript function doMultiplicationTable to create the table. Let’s have a look at that.

Click here to view code image

function doMultiplicationTables() {

    // get the multiplication table number from the web page
    var tableTextElement = document.getElementById("tableNumberText");
    var tableNumberText  = tableTextElement.value;
    var tableNumber = Number(tableNumberText );

    // get the multiplication table list from the web page
    var multiplicationTableListElement =
        document.getElementById("multiplicationTableList");

    // count through the  table producing results
    for (let i=1; i<=12;i=i+1) {
        // calculate the result
        let resultNunber = tableNumber * i;

        // create a result strung
        let resultString = i + " times " + tableNumber + " is " + resultNunber;

        // make  new list item
        let listItem = document.createElement("li");
        // set the text of the new list item to the result string
        listItem.innerText=resultString;
        // add it to the multiplication table list
        multiplicationTableListElement.appendChild(listItem);
    }
}

The most interesting part of this function is the last three statements, which create a new element and add it to the list. Let’s take a look at how they work.

CODE ANALYSIS

Building HTML from JavaScript

Take as your starting point the example application in the Ch06 Repeating actions\Ch06-07 Times Tables HTML generator folder. Open this application and then press F12 to open the Developer View.

Question: Does the program work?

Answer: You can test the program by entering a multiplication table value into the web page and pressing the Make the multiplication table button. You will see a display like the one shown previously in Figure 6-5.

Question: How do we create new web page elements?

Answer: The method createElement is provided by the document object. The method will make a new HTML element. Let’s make another list item to add to the multiplication table list. We give createElement a string that specifies the type of element we want. In this case, we want a list item, so we use the string “li.” Type in the following and press Enter:

Click here to view code image

> var newElement=document.createElement("li");

Now that we have our new element, we can set the innerText that it contains. Type in the following and press Enter:

Click here to view code image

> newElement.innerText="Hello world";

We now have an HTML element that is a list item containing the text Hello world.

Question: How do we add a web page element to an element on the page?

Answer: We can add a new child to any HTML element using the appendChild method to add a new child to the element. First, we need to find the element we want to add to. Type the following statement and press Enter:

Click here to view code image

> var multiplicationTableListElement = document.getElementById("multiplicationTableList");

We now have a variable called multiplicationTableListElement that refers to the list holding the multiplication table. Let’s add our new element to this. Type in the following statement and press Enter.

Click here to view code image

> multiplicationTableListElement.appendChild(newElement);

If you look back at the web page you will discover a new line has appeared underneath the last line of the times table. This line was added by us just now:

The page allows the user to enter the number for which the multiplication table is needed. Here, the value 2 is entered. The text that reads 12 times 2 is 24, Hello world" is displayed on the screen.

This new element is not part of the HTML file; it is part of the document object that is being maintained by the browser.

Question: Can we just keep adding lines to the list?

Answer: Yes, you can. In fact, there is a bug in our solution, which means that it just keeps adding multiplication tables to the list. If you press the Make the multiplication table button again, you will discover that another table will be added to the page:

Question: Can a program delete items from an element?

Answer: Yes, it can. We can delete the element at the start of the list by entering the following:

Click here to view code image

> multiplicationTableListElement .removeChild(timesTableListElement.children[0])

The removeChild method is given a reference to an element that is then removed from the list. In the statement above, the reference that is supplied is a reference to the element at the start of the list. If you look at the web page display, you will find that the first result has been removed.

Deleting elements from a document

In the preceding Code Analysis, we discovered a bug in the multiplication table application. When you select a new multiplication table, the results are added to the end of the existing one. Fortunately, we also discovered a method we can use to remove children from an element. We can use this method to “clean up” the list prior to adding new elements. To do this, we can use another loop construction called a while loop. A while loop repeats a statement as long as a condition is true.

Figure 6-6 While loop

Figure 6-6 above shows the structure of a while loop. The while loop will perform the test and then, if the test is “truthy,” it will perform the statement. It will then loop back and repeat this process until the test is “falsey.” We can use this to create some JavaScript that will delete child elements until there are none left:

Click here to view code image

while(multiplicationTableListElement.children.length > 0)
    multiplicationTableListElement.
    removeChild(multiplicationTableListElement.children[0]);

If this looks a little hard to understand, try converting it into English: “While the number of children is greater than 0, delete a child.” There is a working example of the Times Table program in the Ch06 Repeating actions\Ch06-08 Multiplication Tables HTML generator cleanup folder in the sample programs.

MAKE SOMETHING HAPPEN

More multiplication table fun

Here are some ideas that you might like to investigate.

20s multiplication table

Some people like to show off by knowing their 20s multiplication table. Can you make a change to the program above to make a version that displays the 20s multiplication table? You should be able to do this by changing just one number in the program. If you can’t work out how to do this, you can find my version in the Ch06 Repeating actions\Ch06-09 Twenty times table folder.

Multiplication Table Tester

The page allows the user to enter the number for which the multiplication table is required and checks the multiplication table. Here, the value 2 is entered, and the 'check the multiplication table' button is clicked. The page lists the multiplication table for 2. Few values in the multiplication table are displayed in red color to indicate the incorrect values.

The Multiplication Table Tester produces a multiplication table with some wrong numbers and then challenges the user to find them all. Then the user can press the Check The Multiplication Table button to check which ones are correct. The JavaScript random number generator can be used to decide if a given value is to be displayed incorrectly. The program could work by using a data attribute in each list item that holds the value being displayed by that item. The marking process would be rather like the Theme Park Ride program. It would change the color of the list item depending on whether the displayed value is correct. You can find my version in the Ch06 Repeating actions\Ch06-10 Multiplication Table Tester folder.

What you have learned

This chapter has shown you how to use loops in JavaScript programs. You’ve also picked up some useful programming design tips and discovered how JavaScript code can change the structure of the document being displayed by the browser.

You only really learn how a program should work by making something and trying to use it. If you make a solution for someone, you must be prepared to change the way it works when they think of a better way of using it.

Bugs are a natural consequence of software development. When a fault is reported, your loyalty should be to the process of fixing it, not assigning blame or responsibility.

Some software writing processes, such as repeating behaviors by copying blocks of code, make bugs more likely.

HTML elements can be given data attributes. This allows a program to bind data values directly to items in the document and for data to be embedded in the web page text.

HTML elements can act as containers for other elements. Elements contained in an element are the child elements of the parent. Individual child elements can be accessed using an index value. The index values start at 0.

A JavaScript for loop construction is used to repeatedly perform a statement. The for loop has setup, test, and update behaviors. The setup behavior is performed at the start of the loop. The test is performed after each loop and also before the first loop. If the test evaluates to false, the loop stops. The update behavior is performed after each loop.

A JavaScript for loop construction can be used to manage a control variable counter that can count between two values, allowing a program to work through the children of a container element.

JavaScript provides a for-of construction to work through the elements in a container.

There are JavaScript functions that can be used to create new page elements (document.createElement) and add them as children to existing elements (appendChild). These elements are then rendered by the browser. This makes it possible for JavaScript code to create the contents of a web page programmatically.

There is a JavaScript function (removeChild) that can be used to remove child elements from a container element.

The while loop construction allows a program to repeat a block of statements while a controlling logical expression evaluates to true.

Here are some questions that you might like to ponder about the content of this chapter:

Does every program contain bugs?

It is almost impossible to prove that a given program does not contain any bugs. Testing only ever proves that bugs exist, not that they don’t. The good news is that not all bugs affect the behavior of the program when in normal use.

Why are lists indexed starting at zero?

This is just the way that JavaScript works. Some languages index their collections starting at 1, but JavaScript starts at 0. You can think of the index as the “distance” down the storage that you need to go to get to the item.

Can any HTML element be a container for other elements?

Yes. The HTML element in a document contains the HEAD and BODY elements. It is also possible for the child of an element to have children of its own, allowing for a hierarchy to be created.

Does adding an attribute to an HTML element change the contents of the web page file?

No. You can think of the HTML file as defining the starting point of the document object that is displayed by the browser. Changes to this object will affect the appearance of the page but they will not change the contents of the HTML file.

What is the difference between let and var?

Both keywords are used to create variables. Variables created with var exist from that point in the program. Variables created with let are destroyed when program execution leaves the block where they were declared. Declaring variables using let is a good idea, as it reduces the chances of variables being reused by mistake.

Could I create an entire web page using JavaScript code?

Yes. Lots of web pages you visit work this way. Rather than having HTML text stored on the server, a site contains a small HTML file and a JavaScript program that loads data from the web and then uses it to build the website. We will be doing more of this in future chapters.

7
Creating functions

What you will learn

Functions are an essential part of program design. You can use functions to break up a large solution into individual components and to create libraries of behaviors that can be used by your programs. We have used some built-in functions (for example, alert) and created event handler functions (for example, doCheckAge). In this chapter, you’ll learn how to create and use functions of your own. You’ll see how to give functions data to work on and how a program can receive results that a function returns. Along the way, you will pick up some tips about error handling.

What makes a function?

Parameters as values

Reference arguments

Double dice

What you have learned

What makes a function?

A function is a chunk of JavaScript that has been given an identifier. A function should be defined before it is used. When JavaScript encounters a function definition, it takes the statements that provide the behavior of the function and stores them, so they are ready for use by the program. A program can call the function and the statements in the function will be performed. We’ve created and called functions already, but now is the time to take a detailed look at how they work. Let’s start with a look at a simple function that just says “hello.”

The screenshot is displayed to show the function in the program. The line, function greeter () is the style sheet function. In line, var output element equals document.getElementById("outputParagraph"), the 'outputparagraph' finds the display element. The line, outputElement.textContent equals "Hello"; sets the display text to "Hello."

This web page contains a function called greeter. The function finds an element on the screen with the ID outputParagraph and displays Hello in that element. Once the function has been defined, a program can call it. A call of a function runs the statements given when the function was defined. The greeter function doesn’t do much, but you can create functions that contain many statements. Remember that your program must define the function before it can be called.

CODE ANALYSIS

Investigating functions

Start by opening the application in the Ch07 Functions\Ch07-01 Greeter Function example code folder. This application contains an HTML page with the output paragraph and a script section containing the greeter function. Open the Developer View by pressing F12.

Question: How do I call a function in my program?

Answer: Up until now, our programs have used functions that have been provided for us by JavaScript (for example, the alert function). But the greeter function is one that we have written. However, we can call it in the same way, simply by entering the name of the function, followed by a pair of braces.

> greeter();

When you press Enter, the greeter function is called. This function does not return a result (we will look at this later) and so the console displays undefined.

<- undefined

However, you will notice that the word “Hello” has now appeared in the browser display. This was displayed by the greeter function when it ran.

A screenshot shows a browser screen. It displays the text "Hello", and the term "greeter" at the top. The right pane of the screen diplays the console, where the greeter () function is undefined.

Question: Can we define functions in the console?

Answer: Yes, we can define our own functions in the console. Type the statement below, which creates a function called alerter.

Click here to view code image

> function alerter() { alert("hello"); };

Press Enter when you’ve typed the above statement, exactly as it is shown. Make sure to use the right kinds of brackets for each part.

<- undefined

The application now contains a new function called alerter. The process of defining a function does not return a value, so the console shows the result as undefined.

The JavaScript that you have just typed contains a statement that calls the alert function, but this has not run because this statement is in the body of the alerter function. Now enter a statement that calls the newly created function:

> alerter();

When you press Enter, the statement will call alerter, which will display an alert:

<- undefined

A screenshot shows a browser screen. An alert box is displayed with the text that reads "This page says hello." The browser console displays the code to call the function alerter().

Question: Can one function call another function?

Answer: Yes, it can. Consider the following functions:

Click here to view code image

function m2(){
    console.log("the");
}

function m3(){
    console.log("sat on");
    m2();
}

Click here to view code image

function m1(){
    m2();
    console.log("cat");
    m3();
    console.log("mat");
}

If m1 is called what will be logged in the console? The best way to figure this out is to work through the functions one statement at a time, just like the computer does when it runs the program. Remember that when a function is complete, the program’s execution continues at the statement following the function call. These functions are in the JavaScript for the Greeter page. You can find out what happens by calling function m1:

> m1();

When you press enter the m1 function is called. This then calls m2 and so on. The output is what you would expect:

the
cat
sat on
the
mat

Question: What happens if a function calls itself? For example, what if the m1 function called m1?

Answer: Making a function call itself is a bit like arranging two mirrors so that they face each other. In the mirrors, you see reflections going off into infinity. Does JavaScript go off into infinity when a function call itself? Let’s create a function and find out. Enter the following function definition:

Click here to view code image

> function mirror() { mirror(); };

The mirror function just contains one statement that calls the mirror function. What happens when we create the function. Press Enter to find out.

<- undefined

Nothing happens. Creating a function is not the same as running it. However, we now have a function called mirror that calls itself. Let’s call mirror and see what happens:

> mirror();

When you press Enter, JavaScript will find the mirror function and start obeying the statements in it. The first statement in mirror is a call of the mirror function, which JavaScript will start to execute. The program is stuck in a loop, but it does not get stuck forever. After a while, the console stops with an error:

A screenshot shows a browser screen. The right pane of the screen shows a program with mirror function (), where the statements are in a loop. The left pane of the screen displays the text "Greeter."

Each time a function is called, JavaScript stores the return address (the place it must go back to) in a special piece of memory called the “stack.” The idea is that when a running program reaches the end of a function, it grabs the most recently stored return address from the top of the stack and returns to where that address points. This means that as functions are being called and returned, the stack grows and shrinks.

However, when a function calls itself, JavaScript repeatedly adds return addresses to the stack. Each time the function calls itself, another return address is added to the stack, at the top. The stack is finite in size, and when this size is exceeded, JavaScript stops the program.

Programmers have a name for a function that works by calling itself: recursion. Recursion is occasionally useful in programs, particularly when the program is searching for values in large data structures. However, I’ve been programming for many years and have used recursion only a handful of times. I advise you to regard recursion as strong magic that you don’t need to use now (or hardly ever). Loops are usually your best bet for repeating blocks of code.

Figure 7-1 shows the form of a JavaScript function definition. We can work through each of these items in turn. The keyword function tells JavaScript that a function is being defined. JavaScript will allocate space for the function and get ready to start storing function statements. The word function is followed by the identifier of the function. We must create an identifier for each function we define. Because a function is associated with an action, it’s a very good idea to make the name reflect this. I give functions names in the form verbNoun. The verb specifies the action the function will perform, and the noun specifies the item it will work on. An example would be doMultiplicationTables.

Figure 7-1 Function definition

After the function identifier, we have the arguments that are fed into the function. The arguments are separated by commas and enclosed within parentheses. Arguments provide a function with something to work on. So far, the functions we’ve created haven’t had any arguments, so there has been nothing between the two parentheses. Finally, the definition contains a block of JavaScript statements that form the body of the function. These are the statements that will be obeyed when the function is called.

Give information to functions

The greeter function shows how functions can be used, but it isn’t really that useful because it does the same thing each time it’s called. To make a function truly useful, we need to give the function some data to work on. You’ve already seen many functions that are used in this way. The alert function accepts a string to display in the alert box. The Number function accepts an input to be turned into a numeric value. We could make a version of the greeter function that accepts a message to be displayed:

Click here to view code image

function greeter(message) {
  var outputElement = document.getElementById("outputParagraph");
  outputElement.textContent = message;
}

CODE ANALYSIS

Investigating arguments

The new version of greeter is in the example application Ch07 Functions\Ch07-02 Greeter Arguments. Open this application and then open the Developer View by pressing F12.

Question: How do I give a function call an argument?

Answer: We can give a function an argument by putting something between the braces in the call of the function:

> greeter("Hello from Rob");

When you press Enter, the greeter function is called and the string Hello from Rob is passed as an argument to the function call.

<- undefined

The greeter function does not return a value, so the console displays undefined. However, you will notice that the phrase Hello from Rob has now appeared on the browser display. This was displayed by the greeter function when it ran.

A screenshot shows a browser screen. The right pane of the screen diplays the console, in which the the string "Hello from Rob" is defined as an argument in the greeter function. The left pane of the browser screen shows the function greeter and the string "Hello from Rob" is displayed.

Question: What happens if I omit the argument from the function call?

Answer: This is bad programming practice. We’ve told JavaScript that the greeter function accepts an argument, and then we failed to supply an argument when we called it. Let’s try it. Enter a call of greeter with no arguments.

> greeter();

You might think that this would cause an error. The greeter function is expecting to receive something that is missing from the call. If you’ve used other programming languages, for example C++ or C#, you will be used to getting errors if you make this mistake. However, it turns out that JavaScript is much more relaxed about this. There is no error, but there’s no greeting either:

A screenshot shows a browser screen. The right pane of the screen diplays the console, in which the the function greeter() is displayed without an argument. The left pane of the browser screen shows the text, "Greeter."

This is what has happened:

The JavaScript system notices that there is an argument missing from the call.

It supplies the function with the value undefined for the missing argument.

The function sets the textContent property of the output paragraph to undefined. This is not displayed by the browser, so the text on the screen disappears.

If we are concerned about calls with missing arguments, we can make a version of the greeter function that checks to see if it has been given an argument:

Click here to view code image

function errorGreeter(message) {
  if(message == undefined) {
    alert("No argument to greeter");
  }
  else
  {
    let outputElement = document.getElementById("outputParagraph");
    outputElement.textContent = message;
  }
}

The function above is called errorGreeter. It checks the message it has been supplied with and if the message is undefined it displays a warning alert. Otherwise, it displays the message. This function is in the scripts of the example program. Try calling errorGreeter in the browser console with a missing argument:

> errorGreeter();

When you press Enter, you will see an alert because the function was not supplied with an argument.

A screenshot shows a browser screen. An alert box is displayed with the text that reads "This page says no agruments to greeter." The browser console displays the errorGreeter() function without an argument.

If you call errorGreeter with an argument, you will see that it displays the message as it should.

Question: What happens if I call a function with too many arguments?

Answer: We could try this:

Click here to view code image

> greeter("Hello world", 1,2,3, "something else");

If you call greeter as above, JavaScript will not produce any errors, but the greeter function will ignore the extra arguments.

Arguments and parameters

From the title of this section, you might expect that we will have a difference of opinion, but in JavaScript, the word argument has a particular meaning. In JavaScript, “argument” means “that thing you give to the call of a function.”

greeter("Hello world");

In the above statement, the argument is the string Hello world. So when you hear the word “argument,” you should think of the code that is making a call of the function. In JavaScript, the word parameter means “the name within the function that represents the argument.” The parameters in a function are specified in the function definition.

function greeter(message)

This is the definition of a greeter function that has a single parameter. The parameter has the identifier message. When the function is called, the value of the message parameter is set to whatever has been given as an argument to the function call. Statements within the function can use the parameter in the same way as they could use a variable with that name.

MAKE SOMETHING HAPPEN

Parameters as values

When a function is called, the value of the argument is passed into the function parameter. What exactly does this mean? The following program contains a function (with the interesting name whatWouldIDo) that accepts a single parameter. The function doesn’t do much; it just sets the value of the parameter to 99.

Click here to view code image

function whatWouldIDo(inputValue) {
  inputValue = 99;
}

This function is part of the application in the Ch07 Creating functions\Ch07-03 Parameters as values folder in the example code. Open this application and then open the Developer View by pressing F12. First, we are going to create a variable and put a value into it:

> var test=0;

When you press Enter, the console will create a variable called test that contains the value 100. We can use the test variable as an argument to the whatWouldIDo function:

> whatWouldIDo(test);

When the function has been called, the question we must consider is “What value does test now contain?” Does it contain 0 (the value set when it was created), or does it contain 99 (the value set in the function whatWouldIDo)? We can answer the question by asking the console to display the value of test:

> test
<- 0

When a function is called, the value in the argument is copied into the parameter. So any changes to the parameter will not affect the argument at all.

Multiple parameters in a function

A function can have multiple parameters. We might want a greeter function that can display text in different colors. We could add a second parameter that contains a color name:

Click here to view code image

function colorGreeter(message, colorName) {
  var outputElement = document.getElementById("outputParagraph");
  var elementColorStyle = "color:"+colorName;
  outputElement.textContent = message;
  outputElement.style=elementColorStyle;
}

This function creates a style element using a supplied color name. The style is then applied to the output element along with the greeting text. We then provide arguments giving the string to be displayed and the color of the text:

Click here to view code image

colorGreeter("Hello in Red", "red");

WHAT COULD GO WRONG

Muddled arguments

The colorGreeter function has two arguments that are mapped onto the two parameters that are used inside the function. The first argument has the greeting text, and the second argument has the name of the color to be used for the text. It is important that these arguments are supplied in the correct order.

Click here to view code image

colorGreeter("red", "Hello in Red");

This call of colorGreeter has supplied the color name before the greeting text. In other words, they are the wrong way round. This would result in the colorGreeter trying to display the message “red” in the color “Hello in Red.” This would not cause an error, but it would result in the program not doing what you want. So when we make calls to functions, we need to make sure that the arguments that are supplied are given in the same order as the parameters. You can find the colorGreeter function in the Ch07 Creating functions\Ch07-04 Color Greeter folder.

Using references as function arguments

In a JavaScript program there are essentially two kinds of variable. There are variables that contain a value and variables that contain a reference to an object.

var age=12;

This statement creates a variable called age, which contains a number with the value 12.

Click here to view code image

var outputElement = document.getElementById("outputParagraph");

This statement creates a variable called outputElement, which contains a reference to an HTML element in the page document. This is how our JavaScript programs have located the page elements to be used to display information for the user. We can pass references into function calls as arguments:

The screenshot is displayed to show the function makegreen. In line, <p id equals outputparahgraph"> This is output text </p>, the paragraph is displayed for the output. The line, function makegreen (element) represents the function, and the line element.style equals "color: green"; sets the color of the element parameter to green.

The HTML page above contains a function called makeGreen. The function makeGreen has a parameter called element. The function sets the style of the element parameter to the color green. A program can use this function to make any given HTML element green.

makeGreen(outputElement);

MAKE SOMETHING HAPPEN

Reference arguments

The function makeGreen is declared in the example application Ch07 Creating functions\Ch07-05 Reference arguments folder in the example code. Open this application and then open the Developer View by pressing F12. First we are going to get a reference to the display paragraph.

Click here to view code image

> var outputElement = document.getElementById("outputParagraph");

When you press Enter, a variable called outputElement is created that contains a reference to a paragraph on the screen. Now use this variable as an argument to a call of makeGreen:

> makeGreen(outputElement);

This will cause the text of the paragraph on the web page to turn green because the makeGreen function has set the style property of the element to which it has received a reference:

A screenshot shows the resulyt of makegreen function. The right pane of the screen diplays the console, in which the the function makegreen with outputElement as the argument. The left pane of the screen displays the output that reads "This is output text." The output text is displayed in green color.

What happens if we give makeGreen the wrong kind of argument? Try this:

> makeGreen(21);

The result of this statement is that nothing happens. No error is produced even though it is not meaningful to try to set the style of a numeric value to 21. Any mistakes that you make with function arguments will not produce errors; instead, the program will just keep running.

Arrays of arguments

There is another way that we can pass arguments into a JavaScript function—an array of items. We will discuss arrays in detail in the next chapter. An array is a form of collection. We have already seen one form of collection. The unordered list that we used to display ride information in the Theme Park in Chapter 6 held elements in the form of an array of items. We used the for–of loop construction to work through the array. If you’re not sure about how this works, take a moment to return to Chapter 6 and read “Work through collections using for-of.” Within a function, the keyword arguments means the array of arguments that were given when the function was called.

The screenshot shows a program to explain the array of arguments. The line, let total equals 0; sets the total to 0. The line, for (value of arguments) works through the arguments, and the line, total equals total plus value; add each value in the arguments to the total. In the line, var outputElement equals document.getElementById("outputParagraph"); the text "outputparagraph" gets a reference to the output element. The line, output.Element.textContent equals total; displays the output element.

The function calculateSum shows how this works. It uses a for-of loop to calculate the total of all the arguments given to the function call. This total value is then displayed on the page. The function can be called with any number of numeric arguments:

Click here to view code image

calculateSum(1,2,3,4,5,6,7,8,9,10);

This would display the value 55. Of course, if you do something silly, you might not get what you expect.

Click here to view code image

calculateSum(1,2,3,"Fred","Jim","Banana");

This call of the function would not cause an error. It would display the result 6FredJimBanana. This is because of the way that JavaScript combines strings and numbers. You can find out more in Chapter 4 in the section “Working with strings and numbers.” You can find this sample code in Ch07 Creating functions\Ch07-06 Argument arrays.

Returning values from function calls

A function can return a value. You have seen this in many of the programs we’ve written. Here’s an example:

Click here to view code image

var ageNo = Number(ageText);

This statement uses the Number function. The function accepts an argument (text expressing a number) and returns a value (the text as a numeric value). We can write our own functions that return a value.

Dice spots method

In Chapter 4, we created an application that displays random dice. Each time we wanted a random dice value, we had to perform some calculations. It would be useful to have these calculations in a function that we could use to get a random number of spots.

The screenshot shows a code that performs calculation in a function getDicesSpots (). The line, var spots equals math.floor(math.random() times 6) plus 1; calculates the random result. The line, return spots; returns it to the caller.

This is the function getDiceSpots, which calculates a random number of spots. (Check out the section “Creating random dice” in Chapter 4 for details of how this works.) The last statement in the function uses the JavaScript return keyword to return the calculated number to the caller. This function can be used whenever an application needs a dice value.

A screenshot displays the function doRollDice. In the line, var outputeElement equals document.getElementById("outputParagraph"); the text "outputparagraph" gets a reference to the output paragraph. The line, var spots equals getDiceSpots(); gets the number of spots to displays. The line, var message equals "Rolled;" plus spots; is represented to build the message to display. The line, outputElement.textContent equals message; displays the message.

The function doRollDice is called to display a dice value. It calls getDiceSpots to get the value and then display it. You can see this in action in the example application Ch07 Creating functions\Ch07-07 Returning values, which works in exactly the same way as the dice example in Ch04 Working with data\Ch04-02 Computer Dice, but it uses the doRollDice function.

Creating customizable dice

Sometimes, a program needs a random number in a different range from the 1 to 6 provided by a die. We could use our newfound skills to make a function that accepts minimum and maximum values and then returns a random integer in that range.

A screenshot presents the function getCustomDiceSpots (min, max). The line, var range equals max minus min plus 1; calculates the range of values. The line, var spots equals Math.floor(Math.random() times (range)) plus min; calculates the random value. The line, return spots; returns the result.

The function getCustomDiceSpots is given two parameters that specify the minimum and maximum values of the required random number. It works out the range of numbers that are required (the difference between the maximum and minimum values), calculates a random number in this range, and then adds that number to the minimum value to produce the number of spots. This number is then returned. One of the nice things about functions is that you don’t have to understand how they work to use them.

Click here to view code image

var health = getCustomDiceSpots(70,90);

The above statement creates a variable called health, which contains a random number in the range 70 to 90. It could be used in a video game to set the initial health value of a monster that fights the player. Sometimes, the monster would be slightly harder to kill, which would make the game more interesting to play.

The customizable dice app

I’ve used the getCustomDiceSpots function to make a dice application where the user can select the minimum and maximum values for random numbers that they want to use to play a particular game.

Figure 7-2 shows how the application is used. The user fills in the text boxes for the Min and Max values for the random number that they want and presses the Roll The Dice button to display a random number in that range.

Figure 7-2 Customizable dice

The screenshot allows the user to enter minumum and maximum value. The minimum value entered values is 1, and the maximum value is displayed as 50. The 'Roll the dice' button is clicked and displays te output text that reads "rolled: 42."

The settings in Figure 7-2 will produce a value in the range 1 to 50 that could be used to play a bingo game. Let’s take a look at the code.

The screenshot shows <head> and the <body> codes. The screenshot shows the style sheet for the application and the JavScript source file for the application.

The screenshot shows Min input, Max input, Button that rolls the dice, and Output paragraph.

We have seen this kind of page before. There is some text to tell the user about the application. There are two input fields, which are used to get the minimum and maximum values for the random number to be produced. There is a Roll the Dice button to trigger the generation of the value and an output paragraph that displays the result. This page is very similar to the one used by the Theme Park Ride Selector application in Chapter 6. The function doRollDice is called when the user clicks the button to roll the dice.

Click here to view code image

onclick="doRollDice('minNoText','maxNoText', 'outputParagraph');"

This is the onclick attribute for the Roll the Dice button. This attribute contains a string of JavaScript code that will be obeyed when the button is clicked. If you’re not clear on how this works, take a look in the section “Using a button” in Chapter 2 for a refresh. The JavaScript that runs when the button is clicked makes a call of the function doRollDice.

Click here to view code image

doRollDice('minNoText','maxNoText', 'outputParagraph');

The doRollDice function has three arguments, which are the ID strings for the minNoText, maxNoText, and outputParagraph elements in the web page. The function gets the minimum and maximum values from elements identified by the first two arguments to the function call. It then calculates the random result and then displays the result using the output element identified in the third element. We can take a look at this function to see how it works:

A screenshot explains the function doRollDice with three arguments. The line, var min equals getNumberFromElement(minElementName); gets the minimum value. The line, var max equals getNumberFromElement(maxElementName); gets the maximum value. The line, var spots equals getCustomDiceSpots(min, Max); gets the number of spots. The line var message equals "Rolled:"plus spots; is displayed to build the output message. The line, var outputElement equals document.getElementById(outputElementName); gets the output element. The line, outputElement.textContent equals message; displays the number.

The function looks very small. It gets in the minimum and maximum values, calls getCustomDiceSpots to get the random value, and then displays the result. The function is small because it uses another function called getNumberFromElement to get the maximum and minimum values:

A screenshot displays the function getNumberFromelementName (name). The line, var element equals document.getElementById("name"); gets the input element. The line, var text equals element.value; gets the text from the input element. The line, var result equals "Number (text); convert the text into a result. The line, return result; returns the result.

This function is given the identifier of an input element on the web page as a parameter. It fetches a number from the specified input element. We can use this function in any program that needs to read numbers from the user. It gets a reference to the element with the identifier that has been supplied as a parameter, gets the text from this element, converts the text into a number, and then returns the number to the caller. The function is called twice in the dice application—once to read the maximum value and once to read the minimum value. If I had an application that needed 10 inputs to be read from the screen, I could call this function 10 times in the application.

PROGRAMMER’S POINT

Designing with functions

Functions are a very useful part of the programmer’s toolkit and form an important part of the development process. Once you’ve worked out what a customer wants the application to do, you can start thinking about how you’ll break down the program into functions. Once you’ve specified the behavior of each function in the application, you can write the function headers (in other words, pick the function name, the parameters, and any return value), and then you could even get someone else to write that function for you.

Functions save you from writing too much code. Often, you find that as you write a program, you write code that repeats a particular action. If you do this, you should consider taking that action and turning it into a function. There are two reasons why this is a good idea:

First, it saves you writing the same code twice; and secondly, if a fault is found in the code, you only need to fix it in one place.

Functions also make a program easy to test. You can regard each function as a “data processor.” Data goes into the function via the arguments, and output is produced via the return value. We can write what is called a “test harness” to call a function with test data and then check to ensure the output is sensible. In other words, we can make a program that tests itself. We will look at this later in the book.

Add error handling to an application

The Digital Dice program works well as long as we use it correctly. However, it is not without its problems. It is quite easy to enter invalid values for the minimum and maximum values. You can experiment with the application in the examples folder Ch07 Creating functions\Ch07-08 Custom dice to discover what happens when it fails.

Figure 7-3 shows how the application can be used incorrectly. A minimum value of 50 and a maximum value of 2 is not correct. To make matters worse, the application has displayed a result that might be incorrect. We have no way of knowing if it has worked correctly because we are not sure how the getCustomDiceSpots function behaves if it is given incorrect maximum and minimum values. It turns out that there are also other ways to cause the program problems. A user could press Roll The Dice when the Min and Max input areas are both empty. We need to fix all these things. Fortunately, we have the JavaScript skills that we need to sort this out.

Figure 7-3 Dice errors

The screenshot allows the user to enter minumum and maximum value. The minimum value entered values is 50, and the maximum value is displayed as 2. The 'Roll the dice' button is clicked and displays te output text that reads "rolled: 26."

Finding all the errors in advance

One thing that separates a good programmer from a great programmer is the way that they handle errors. A great programmer will start a project by thinking of all the things that could go wrong when the user starts to use their program. It’s unlikely that they will think of every possible error (users can be very inventive when it comes to breaking things), but they will write down all the errors they can think of and then set out to deal with each error. Then, as the project continues, a great programmer will keep looking for possible errors and keep making sure that the errors that they know about are being handled correctly. In the case of the Digital Dice application, I can think of three things that might go wrong:

The user might not enter anything into the Max or Min inputs.

The user might enter a number outside the correct range for one of the Max or Min inputs.

The user might enter a Min value that is greater than or equal to the Max value.

Now that we have identified the errors, the next thing we need to decide is what the program should do when they are detected. If you are writing a program for a customer, you must discuss with them what is supposed to happen. Do they want the program to assume default values (perhaps a Min of 1 and a Max of 6), or do they want error messages to be displayed? Do they want the error to be a message on the screen or a pop-up alert? These are all important questions that the programmer alone can’t answer. The worst thing that can happen is that you make an assumption concerning what the customer wants. In my experience, making assumptions is a neat way of doubling your workload. You show the customer what you’ve made, they tell you it is not what they want, and you have to do it again. In the case of our customer, we have been told that the program should display a message and turn any invalid input areas on the screen red so that the user knows what to fix. So let’s see how we can use our JavaScript skills to solve this problem.

Let’s start with the error display. These are two style classes that I’m going to use to on the input elements on the web page. The menuInput style is the “normal” style. The program will set the menuInputError style to an input element that contains an invalid entry. Note that this has the background color set to red.

Click here to view code image

.menuInput {
    background-color: white;
    font-size: 1em;
    width: 2em;
}

.menuInputError {
    background-color: red;
    font-size: 1em;
    width: 2em;
}

Our application uses a function called getNumberFromElement to get a number from an input element. Let’s have a look at an improved function to deal with input errors:

A screenshot displays the function getNumberFromElementName (elementId). The line, var element equals document.getElementById("elementId"); gets the input element. The line, var text equals element.value; gets the text from the input element. The line, var result equals Number (text); convert the text into a number. The line, if (isNaN9result)) checks if we have a number. The line element.ClassName equals "menuInputError"; is displayed to indicate an error.

A screenshot displays the function getNumberFromElementName (elementId). The line, if (result greater than max or result less than min), checks if the number is in the range.

CODE ANALYSIS

The getNumberFromElement function

This function bears closer inspection. Here are answers to some questions about it:

Question: What does NaN mean? And what is the isNan function doing?

Answer: We first saw NaN in Chapter 4 when we wrote our first JavaScript to read numbers from the user. It is how JavaScript represents a value that is “not a number.” In this case, the function is using the Number function to convert the text entered by the user into a number. If the Number function fails, either because the text is not numeric or the text is empty, the Number function returns the value NaN because it could not create a number result. The isNaN function takes an argument and returns true if the argument is not a number. The getNumberFromElement function uses isNaN to test the result value produced by the call to Number. If the result is not a number, the function sets the style of the element to indicate that the input was in error and then returns the value NaN to the caller to indicate that a number could not be read.

Question: What are the min and max attributes? Where do they come from?

Answer: We can add min and max attributes to an HTML input element to help the browser validate numbers entered by the user. However, the browser does not enforce minimum and maximum values completely; our program must also play a part in making sure that numbers are entered in the correct range.

Click here to view code image

<input class="menuInput" type="number" id="minNoText" value="1" min="1" max="99">

The HTML above is the input element for the minimum value. The min and max attributes are set to 1 and 99 respectively. The getNumberFromElement function can get the values of these attributes and then use them to perform input validation:

Click here to view code image

var max = Number(element.getAttribute("max"));
var min = Number(element.getAttribute("min"));

The function can then use these values to validate the number entered by the user.

Click here to view code image

if(result>max || result<min){
    // fail because outside range
    element.className="menuInputError";
    return NaN;
}

This is a really good way of handing minimum and maximum values because the values are obtained from the elements on the HTML page and are not held in the JavaScript code.

Question: Why does the function sometimes return the value NaN?

Answer: We’ve discovered that it is possible for the getNumberFromElement function to be unable to deliver a result. This happens when the user doesn’t type in a numeric value or when the value they enter is out of range. The function needs a way of informing the caller that it does not have a valid result, and returning NaN is how you do this in JavaScript. This makes using a function that returns a value that is a kind of “buyer beware” proposition, as the code that called the function must test to make sure that the delivered result was valid. We will see this in action when we look at the error handing version of doRollDice.

These changes to the getNumberFromElement function have addressed the first two errors that we identified. The user must now enter a valid number or the getNumberFromElement function returns the value NaN (not a number). Now the doRollDice function needs to be updated. This version checks that the minimum and maximum values are both numbers. It also checks that the minimum value is less than the maximum value. If either of these conditions is not met, the function displays an alert.

The screenshot labels coding to get the output element, minimum value, maximum value, codes to check for non-numbers, codes to display error message, codes to check maximm and minimum, the codes to display error messages, codes to check maximm and minimum, codes to get the spots value, codes to build the reply, and codes to display the reply.

Figure 7-4 shows the error handling in action. Note that I’ve also made another change to the application, so that it now shows the user the minimum and maximum values that are allowed for each input. This is a great way to reduce the chances of any errors in the first place.

Figure 7-4 Error handling

The screenshot allows the user to enter minumum and maximum value. The minimum value entered values is negative 1, and the maximum value is displayed as 6. The 'Roll the dice' button is clicked and displays the output text that reads "Invalid range values." The minimum value field is highlighted in red to indiacte the error in the minimum value range.

PROGRAMMER’S POINT

You need to attack errors

I can be a very depressing person to have at a project meeting, particularly at the start of the project. I’ll keep searching for things that could go wrong and things we need to worry about. I’ll also try and involve the customer in this process and make sure we find out what should happen when things fail. I’m not doing this because I have a tendency to worry about things (although I probably do). I’m doing this because I don’t want to be tripped up by unexpected problems. If you are making something you care about, you should take the same approach.

Local variables in JavaScript functions

Imagine several cooks working together in a kitchen. Each cook is working on a different recipe. The kitchen contains a limited number of pots and pans for the cooks to share. The cooks would need to coordinate so that two of them didn’t try to use the same pot. Otherwise, we might get sugar added to our soup and custard instead of gravy on our roast beef.

The designers of JavaScript faced a similar problem when creating functions. They didn’t want functions to fight over variables in the same way that two cooks might fight over a particular frying pan. You might think that it would be unlikely that two functions would try to use variables with the same name, but this is actually very likely.

Many programmers (including me) have an affection for the variable name i, which they use for counting. If two functions use a variable called i and one function calls the other function, this could lead to programs that don’t work properly because the second function might change i to a value that the first function didn’t expect.

JavaScript solves this problem by providing a way for each function to have its own local variable space. This is the programming equivalent of giving each cook their own personal set of pots and pans. Any function can declare a local variable called i that is specific to that function call. We declare a variable as local by using the keyword var.

Click here to view code image

function fvar2() {
  var i=99;
}

function fvar1(){
  var i=0;

  fvar2();

  console.log("The value of i is:" + i);
}

When a function returns, all local variables are destroyed. The code above shows two functions that contain local variables. Both fvar1 and fvar2 use a variable called i. If we call f1var, JavaScript follows this sequence:

The function fvar1 is called.

The first statement of fvar1 creates a variable called i and sets it to 0.

The second statement of fvar1 makes a call to fvar2.

The first and only statement of fvar2 creates a variable called i and sets it to 99.

The function fvar2 finishes and control returns to the third statement of fvar1.

The third statement of fvar1 prints out the value of i.

The question we must consider is this: “What value is displayed in the console?” Is it the value 0 (which is set inside fvar1), or is it 99 (which is set inside fvar2)? If you’ve read the first part of this section, you know the value that will be printed is 0. The variables both have the same name (they are both called i), but they each “live” in different functions.

JavaScript uses the word scope when talking about variable lifetimes. The scope of a variable is that part of a program in which a variable can be used. Each version of i has a scope that is limited to the function body in which it is declared This form of isolation is called encapsulation. Encapsulation means that the operation of one function is isolated from the operation of other functions. Different programmers can work on different functions with no danger of problems being caused by variable names clashing with each other. Now take look at this pair of functions:

Click here to view code image

function f2() {
  i=99;
}

function f1(){
  i=0;

  f2();

  console.log("The value of i is:" + i);
}

Can you spot the difference? These two functions don’t use the keyword var to declare their variables. Is this important? Yes. It turns out that variables declared without the var keyword are made global to the whole application, so f1 and f2 are now sharing a single global variable called i. If we call the function f1, it will print the value 99 because the call of f2 will change the value of the global variable i. This means that you should always use var to declare variables in your functions unless you specifically want to share them. In Chapter 4, in the section “Global and local variables,” we discovered a situation where a program needs to have a variable that has global scope. Now we are starting to understand how this works.

Local variables using let

In Chapter 6, in the section “The JavaScript for loop,” we discovered that we could declare local variables using the keyword let. Variables declared using let are discarded when a program leaves the block of statements where they were declared, whereas variables declared using var are discarded when the program leaves the function in which they are declared.

A screenshot displayes the declaration of local variable using the 'let' keyword. The line, var i equals 0; indicates that the version of i exists for the whole function. The line, let i equls 1; indicates that the version of i only exists in this block. The line, var j equals 2; indicates that j exists for the whole function.

The function letDemo shows how this all works. It contains two versions of i. The first version is declared as var and exists for the entire function. The second version is declared inside a block and is discarded when the program leaves that block. Note that within the block it is not possible to use the outer version of i because any references to i will use the local version. In this case, we say that the outer variables is scoped out. The function also contains a variable called j, which is declared inside the inner block. However, because j is declared as var, it can be used anywhere inside the function. These functions are declared in the example program in the Ch07 Creating functions\Ch07-10 Variable scope folder.

If you find this confusing, then I apologize. The best way to understand it is to consider the problem that they are trying to solve (stopping lots of cooks fighting over the same pots and pans) and then work from there. The most important point is to always use var or let when you create a variable. Otherwise, you may find yourself a victim of very strange bugs in your programs.

MAKE SOMETHING HAPPEN

Double dice

Quite a few games use two dice rather than one. Make a version of the dice program that displays the results from two dice. You could even make this super-customizable so that the user can select the range of values to be produced by each die. If you are bit stuck with this, remember that there is nothing wrong with the onClick behavior of a button calling two methods. And that two dice are just one dice (or die) times two. Take a look at my example solution in the examples at Ch07 Creating functions\Ch07-11 Two Dice to discover the sneaky way I made the program work.

What you have learned

In this chapter, you learned how to take a block of code and turn it into a function that can be used from other parts of the program.

You’ve seen that a function contains a header that describes the function, and a block of code that is the body of the function. The function header supplies the name of the function and any parameters that are accepted by the function. When a function is called, the programmer supplies an argument that matches each parameter.

Parameters are items that the function can work on. They are passed by value, in that a copy is made of the argument given in the function call. If the function body contains statements that change the value of the parameter, this change is local to the function body. When an object (for example, a paragraph that has been obtained using the getElementById method) is used as an argument to a function call, the function receives a reference to the object. This allows code in the function body to interact with attributes in the objects, as we saw with the makeGreen function above.

A function can regard parameters as an array and can work through the arguments supplied to the function by using the arguments keyword.

A function returns a single value. This is achieved by using the return statement, which can be followed by a value to be returned. If no value is returned or the function does not perform a return statement, the function will return a special JavaScript value called undefined, which is used to denote a missing value.

The scope of a variable in a program is that part of the program in which the variable can be used. Variables created inside the body of a function using the keyword var have a scope that is local to the function and cannot be used by statements outside that function.

When creating software, it is important to consider potential errors at the start of the project rather than finding out about them later.

Here are some questions that you might like to ponder about the use of functions in programs:

Does using functions in programs slow down the program?

Not normally. There is a certain amount of work required to create the call of a function and then return from it, but this is not normally an issue. The benefits of functions far outweigh the performance issues.

Can I use functions to spread work around a group of programmers?

Indeed, you can. This is a very good reason to use functions. There are several ways that you can use functions to spread work around. One popular way is to write placeholder functions and build the application from them. A function will have the correct parameters and return value, but the body will do very little. As the program develops, programmers fill in and test each function in turn.

What is the maximum number of arguments that you can give to a function call?

We have seen that you can add lots of arguments to a call of a function. JavaScript does not place a limit on how many arguments you can pass in, but if you find yourself passing more than seven or eight, I’d advise you to think about how you are delivering the information to your function. If you want to pass a number of related items into a function, you might want to create an object (which we will explore in the next chapter) and pass in a reference to the object, rather than passing in lots of different values.

What is the difference between var and let when creating variables inside a function body?

Great question. Both keywords can be used to create a variable that exists within the block of code that is a function body. The difference between the two is that a variable created using var will exist within the function body from that point onward. A variable created using let will disappear at the end of the block in which it is created.

I’m still not clear on the difference between var and let in JavaScript. Why do we have them?

Remember that the problem that we are solving is that we don’t want a program to fail because programmers put values with different meanings into the same variable. If one part of a program used a variable called total to hold the total sales and another part used a variable called total to hold the total price, the program would fail. You would have the same problems if you used a single pan to make both custard and gravy while cooking a meal.

A variable created with the let keyword only exists within the block where it is declared, which means that it cannot be affected by statements running outside that block. This would be like you grabbing a clean pan, making the custard, and then washing the pan and putting it away before it was used for anything else. The var keyword allows you to create a variable that exists from the point of declaration and can be used to share a value around parts of a program or function.

Generally, you should create variables by using the let keyword and only use var if you really want the value in the variable to be used in other places in the function body. Note that a variable in a function that was created with the keyword var will disappear when the program exits the function.

How do I come up with names for my functions?

The best functions have names given in a verb-noun form. getNumberFromElement is a good name for a function. The first part indicates what it does, and the second part indicates where the value comes from. I find that thinking of function names (and variable names, for that matter) can be quite hard at times.

What do I do if I want to return more than one value from a function?

JavaScript functions can only return a single value. However, in the next chapter we will discover how to create data structures that can contain multiple values that can be returned by functions.

8
Storing data

What you will learn

You might find this surprising, but you’ve already learned most of what you need to know to tell a computer what to do. You can write a program that gets data from the user, stores it, makes decisions based on data values, and repeats behaviors using loop constructions. You also know how to use functions to break a solution down into components. These are the fundamentals of programming, and all programs are built on these core capabilities.

However, there is one more thing you need to know before you can write most any kind of program. You need to be able to write programs that can manage large amounts of data. In this chapter, you’ll learn just that, along with some extremely powerful JavaScript techniques for working with the HTML Document Object Model (DOM) that underpins the display of a page.

Collections of data

Investigating arrays

Use the debugger to see code run

Highlight the best and worst sales locations

What you have learned

Collections of data

Your fame as a programmer is beginning to spread far and wide. Now the owner of an ice-cream parlor comes to you and asks that you write a program to help her track sales results. She currently has six stands around the city selling ice cream treats. What she wants is quite simple—she wants a program where she can enter the sales value from each stand and then get the total sales from all of them, as well as the best and worst sales. She wants to use this analysis to help her plan the location of her stands and reward the best sellers. If you get this right, you might be getting some free ice cream, so you agree to help.

As usual, the starting point for your program is a design that shows how the application should look. Figure 8-1 shows what the customer has drawn up. She wants to enter the sales values and then press a Calculate button to display the analysis. Because you have read Chapter 7 and you know about error handling, you ask her about the upper and lower limits on the data values and what the program should do if any of the values are out of range. Your customer hasn’t thought of this, but you discuss the application and agree on some additions to the design as shown in Figure 8-2.

Figure 8-1 Ice cream calculator

A screenshot displays the ice calculator, wich allows the user to enter the sale values in each stands. Once the calculate button is clicked, It displays the total, highest and lowest values.

Figure 8-2 Ice cream calculator errors

A screenshot displays the ice calculator, wich allows the user to enter the sale values in each stands. Here, the value in stand 1 is empty, the value in stand 2 and stand 3 are out of the given range. Once the calculate button is clicked, It displays a output that reads "please enter the numbers in the correct range." The first three fields are highlighted in red color to indicate the error.

Ice cream sales

Now that you have a specification, all you must do now is write the actual program itself. The program will need variables to hold the sales values entered by the user, and it can use logical expressions to compare sales values and choose the largest (so that it can find the biggest and smallest sales). You also know from earlier chapters how to display results to the user by setting the innerText of a paragraph in the page. We could start with the HTML for the application:

Click here to view code image

<!DOCTYPE html>
<html lang="en">

<head>
  <title>Ice Cream Sales</title>
  <link rel="stylesheet" href="styles.css">
  <script src="icecreamsales.js"></script>
</head>

<body>
  <p class="menuHeading"> &#127846; Ice Cream Sales</p>

  <p>
    <label class="menuLabel" for="s1SalesText">Stand 1 sales (0-10000):</label>
    <input class="menuInput" type="number" id="s1SalesText" value="0" min="0"
    max="10000">
  </p>

  <p>
    <label class="menuLabel" for="s2SalesText">Stand 2 sales (0-10000):</label>
    <input class="menuInput" type="number" id="s3SalesText" value="0" min="0"
    max="10000">
  </p>

  <p class="menuText" id="outputParagraph">
  </p>

  <p>
    <button class="menuText" onclick="doCalc()">Calculate</button>
  </p>

</body>

</html>

This HTML contains an input field for each of the six sales that are to be entered by the user. (The listing above only shows the first two to save space.) Each input field has an id attribute so that the program can find it and load the value stored in it. The input field uses a new feature of HTML that we have not seem before, the label, as shown in Figure 8-3.

Figure 8-3 Single data entry element

Labeling HTML input elements

Each of the elements on the application has a label next to it. In Figure 8-3, the label shows that the input is for the sales of ice cream stand number 1. In earlier programs, we have just displayed text next to the input element to label it, but it turns out that there is a better way to label inputs on an HTML page. We can use the label element to explicitly link a label with an input.

Click here to view code image

<p>
  <label class="menuLabel" for="s1SalesText">Stand 1 sales (0-10000):</label>
  <input class="menuInput" type="number" id="s1SalesText" value="0" min="0"
  max="10000">
</p>

The label and the input are held inside a paragraph. The label contains the label text for the input. It also contains a for attribute that matches the id of the target of the label. Both the label and the input are assigned style sheet classes to manage their appearance on the page.

Calculate total ice cream sales

The HTML contains a button that the user presses to perform the calculation. When this is pressed, the JavaScript function doCalc is called. This function must get the values from the input elements on the HTML page and then calculate the results that the user wants to see.

A screenshot displays the function doCalc(). It consists of variables such as sales 1, sales 2, sales 3, sales 4, sales 5, and sales 6. Here, the line sales6 - getNumberFromElement("s6SalesText"); get the sale values from the input.

This is the first part of the function doCalc. The function runs when the user presses the Calculate button. It calls another function with the name getNumberFromElement that we created in the “The customizable dice app” section in Chapter 7. This function is supplied with a string containing the id of the element in the HTML, and it returns the value that the element contains. Once each sales value has been obtained, the program then works out the total sales value by adding all the sales together.

Find the highest ice cream sales

Finding the total sales was easy, so now we need to add the code to find the highest and the lowest sales. Fortunately, we know about the use of relational operators to compare values and logical expressions to combine the comparisons. You can refresh you understanding of these in Chapter 5 in the “Boolean expressions” section. With that knowledge, we can write a JavaScript statement that can determine whether the sales from ice cream stand 1 are the largest:

The code above uses an if construction to decide whether the sales from stand 1 are the largest. The sales from stand 1 are largest if sales1 is greater than the sales values from the other five stands. The logical expression checks to see whether the sales from stand 1 are greater than the sales from stand 2, stand 3, stand 4, and stand 5. The expression sets the variable highestSales to the value in sales1 if sales1 is the largest value.

One problem with this design is that our program needs a test like this for all six sales values, so we need to write five more tests. Then we need another six tests to determine the lowest sales value, and if the ice cream parlor owner sets up more ice cream stands, this would make our program even more complex.

We have hit this problem because we have started from the wrong place. Sometimes, it is a good idea to use an existing program as the basis of a new one, but we have discovered that a design created to work with two values (the maximum and minimum values for a random number) does not scale up very well. We must do a lot of work to extend this structure to read in and manipulate six values.

I’ve watched a lot of people learn to program, and I’ve seen quite a few work much harder than they needed to because they took something that they know how to do and tried to extend it to do a different task. This is a bit like trying to dig the foundations of a house with a spoon just because you know how use a spoon but don’t fancy learning how to drive the mechanical digger. We have already decided that the best programmers are “creatively lazy.” This might be a good point to try for some creative laziness. If you find yourself having to repeat chunks of code, you might want to stop and think about a better way of doing this. If you really want to do this the hard way, I’ve put my partially completed version of the program in the Ch08 Storing data\Ch08-01 Unworkable Ice Cream Sales folder.

Creating an array

JavaScript also provides an array component that can be used to create indexed storage of a collection of data values. Each item in an array is called an element. A program addresses a particular element in the array by using an indexer, which is a number that identifies the element in the array. Some programmers refer to an indexer as a subscript. Let’s investigate how arrays work.

MAKE SOMETHING HAPPEN

Investigating arrays

Start by opening the application in the Ch08 Storing data\Ch08-02 Array Ice Cream Sales folder in the example code. This application works, so you can enter some data and check the results. We are just going to investigate arrays from the developer console. Open the Developer View by pressing the function key F12. Now we can start typing commands into the JavaScript command prompt. The first thing we are going to do is create an empty array. Type in the statement below:

> var sales = [];

When you press Enter, the JavaScript console creates an empty array with the identifier sales. This action does not return a result, so the console displays the message undefined:

> var sales = [];
<- undefined

We can ask the JavaScript console to show the contents of any variable by entering the name of that variable. This works with an array, too. Type in the identifier sales and press Enter.

> sales
<- []

The console shows us that the sales array is empty by displaying two brackets with nothing between them. Now lets store a sales value in the array. This statement will add an element at the start of the array:

> sales[0] = 100;

When you press the Enter key, JavaScript must store the value 100 in the array element with the index 0.

> sales[0] = 100;
<- 100

This element does not exist, so JavaScript adds it to the array automatically. Because an assignment statement returns the value that is assigned, the console displays the value 100, which is what was assigned to the array element. We can view the contents of the array again to see what has changed. Type in the identifier sales and press Enter.

> sales
<- [100]

The console shows us that the sales array now contains a single value. We can use an array element as we would use any other variable. What do you think the following statement would do? Type it in and find out.

> sales[0] = sales[0] + 1;
<- 101

This statement adds 1 to the element at the start of the array. Let’s add a second element to the array. We create the new element just by storing something in it.

> sales[1] = 150;
<- 150

This element does not exist, so JavaScript adds it to the array automatically. Because an assignment statement returns the value assigned, the console displays the value 150. Let’s see what has changed in the array. Type in the identifier sales and press Enter.

> sales
<- [101, 150]

JavaScript shows us the element at the start of the array (which has 101 in it) and the next element (which has 150 in it). JavaScript will add new elements to the array each time whenever it needs to. You can think of the array as “stretching” to hold whatever items it needs to.

The JavaScript in the Ch08 Storing data\Ch08-02 Array Ice Cream Sales example program uses arrays to store the sales values. Below, you can see the statements in the program that get the data into the array for analysis.

A screenshot shows the source code to store sales values using arrays. The line, var sales- []; is displays the sales array. The line, sales[0] -getNumberFromElement("s0SalesText"); stores sales value in each element of the array.

The statements above create an array called sales and then set elements in the array with the sales values from the elements on the HTML page. Note that because the array elements are indexed from 0, I’ve changed the IDs for the input elements to match. In other words, the element at the start of the array has an index value of 0 and is assigned a value from an element with an ID that matches.

Click here to view code image

sales[0] = getNumberFromElement("s0SalesText");

PROGRAMMER’S POINT

Counting from zero is just something you will have to get used to

If you are used to counting from 1, you will find that the way that arrays count from zero is a bit irritating. However, you will just have to get used to it, as it is how JavaScript (and lots of other programming languages) work. Just remember that an array containing six elements (like the sales array above) will index these in the range 0 to 5. Note that this means that sometimes you will have count in one way for the program (array elements 0 to 5) and another for the user (ice cream stands 1 to 6).

Processing data in an array

Storing the sales in an array makes it easy for a program to work through the elements in it. We can access individual elements by using index values, or we can use the for-of loop to work through the elements.

The screenshot displays the data processing in the array. The line, total-0; indicates that the value of sales is 0. The line, for (let saleVale of sales), works through the sale array. The line, total -total plus saleValue; is dislayed to add each sales value to the total.

The statements above work through the sales array and calculate the total number of sales. The great thing about this code is that it would work for any size of array.

Finding the highest and lowest sales values

Another request the customer made was for the program to find the highest and lowest sales in the set of results. Before you write the code to do this, it’s worth thinking about the algorithm to use. In this case, the program can implement an approach very similar to one that a human would use. If you gave me some numbers and asked me to find the highest value, I would compare each number with the highest value I had seen so far and update the current highest value each time I found a larger one. In programming terms, this algorithm would look a bit like the following. (This is not JavaScript as such; a description like this is sometimes called pseudocode. It looks something like a program, but it is there to express an algorithm, not to run inside a computer.)

Click here to view code image

if(new value > highest I've seen)
   highest I've seen = new value

At the start, we set the “highest I’ve seen” value to the value of the element at the start of the array because this is the highest we’ve seen at the start of the process. I can put this behavior into a function that will calculate the highest value in any array that is passed into it.

A screenshot displays the source code to find the highest sales values using the function getHighest(inputArray). The line, var max -inputArray[0];

A program can use the getHighest function to get the highest value from any array of values. We can create helper functions called getHighest, getLowest, and getTotal to use in our application.

Click here to view code image

function doCalc() {

    var sales = [];

    sales[0] = getNumberFromElement("s0SalesText");
    sales[1] = getNumberFromElement("s1SalesText");
    sales[2] = getNumberFromElement("s2SalesText");
    sales[3] = getNumberFromElement("s3SalesText");
    sales[4] = getNumberFromElement("s4SalesText");
    sales[5] = getNumberFromElement("s5SalesText");

    var totalSales = getTotal(sales);
    var highestSales = getHighest(sales);
    var lowestSales = getLowest(sales);

    var result = "Total:" + totalSales + " Highest:" + highestSales +
                 " Lowest:" + lowestSales ;

    var outputElement = document.getElementById('outputParagraph');

    outputElement.textContent = result;
}

The completed version of doCalc is shown above. It creates a sales array, uses the analysis functions to create the results, and then displays them. You can find this version of the program in the Ch08 Storing data\Ch08-02 Array Ice Cream Sales examples folder.

WHAT COULD GO WRONG

Detecting invalid sales values

The ice cream sales application configures the input elements in the HTML document to have an input type of number.

Click here to view code image

<input class="menuInput" type="number" id="s0SalesText" value="0" min="0" max="10000">

However, using this input type would not stop the user from directly entering invalid values:

In this case, the user has accidentally pressed the minus key when typing in the number and entered a negative value. The good news is that the getNumberFromElement function that the program is using to read the sales value will return a result of NaN (not a number) when it reads a value outside the min and max settings for an element. (You can learn more about how this works in Chapter 7 in the section “Add error handling to an application.”)

The bad news is that our program will not handle this correctly. We can fix the problem by using the way that JavaScript works with numbers. Remember that any mathematical calculation involving the value “not a number” will return a result of “not a number.” So if the total of all the sales values is not a number this means that at least one of the sales values is not a number. This is something our program can test for.

Click here to view code image

var totalSales= getTotal(sales);

var result;

if (isNaN(totalSales)) {
    result = "Please enter numbers in the correct range"
}
else {
    var highestSales = getHighest(sales);
    var lowestSales = getLowest(sales);

    result = "Total:" + totalSales + "Highest:" + highestSales +
             "Lowest:" + lowestSales;
}

The code above shows how this works. If the totalSales value is not a number, the result variable is set to an error message. Otherwise, result is set to the calculated values. You can find this version of the program in the example folder Ch08 Storing data\Ch08-03 Error handling Ice Cream Sales.

Build a user interface

The program that we have created meets the specification set by the customer. Which makes the next phone call from our customer rather unwelcome. She says she has some good news. Her company has just got another two ice cream stands. This means that we will have to add two extra elements to the HTML for the application and then make sure that the data analysis program loads these new values in correctly.

A way to make our lives easier, in terms of both creating the HTML data entry page and processing the data, is to make more use of the Document Object Model (DOM) that underpins the application. In Chapter 6, in the “Building web pages from code” section, we made some use of this when we created the Multiplication Table Generator application, which generates HTML output elements using a for loop and adds the elements to the document for display to the user. If you are not sure how this works, take a look at the Code Analysis section “Building HTML from JavaScript” in Chapter 6.

The source code of the ice cream sales application is displayed. The line, <title> Ice Cream Sales </title> is displayed to set title for the page. The line, <link rel equals "stylesheet" href equals "styles.css"> represents the style sheet for the application. The line, <body onload equals "doBuildSalesInputItems('salesItems', 0, 10000, 6); "> represents the function called to build the page. The line, <p class equals "menuHeading"> 🍦 Ice Cream Sales </P> represented for the heading of the page.

The source code of the ice cream sales application is displayed. The line, <div id equals "salesItems"> is represented for storing the sales items. The line, <p Class equals "menuText" id equals "outputParagraph"> displays the output paragraph.

This is the HTML page for a version of the ice cream sales program that automatically generates the input paragraphs. The paragraphs will be generated by the doBuildSalesInputItems method, which is connected to the onload event. We first saw the onload event in Chapter 3 in the “Create a ticking clock” section when we used onload to start the clock ticking when the clock page was loaded.

For the ice cream sales application, the onload event will trigger the creation of the input items when the page is loaded. The input items will be added as children of the div element with the salesItems ID. A div element is an HTML element that is used to group things. We first saw div in Chapter 3 in the “Formatting parts of a document using div and span” section.

Click here to view code image

doBuildSalesInputItems ('salesItems',0, 10000, 6);

The doBuildSalesInputItems function is called with four arguments:

The ID string of the element that will contain the input items to be created. The input items will be added to the children of that element.

The minimum value that can be input to this element. This value is used to create the input element. In the case of our application, the smallest number of sales is 0.

The maximum value that can be input to this element. In the case of our application, the customer has said that sales of more than 10,000 are impossible.

The number of input paragraphs that are to be created. The statement above will create six input elements.

Now that we’ve seen how the doBuildSalesInputItems function is called, let’s look at the function code itself.

A screenshot shows the source code to automatically generate the input paragraph using doBuildSalesInputItems function. The line, for (let itemCount equals 1; itemCount less than or equals to noOfItems; itemCount equals itemCount plus 1) is displayed to loop round for each items to be added. The line, let labelText equals "sales" plus itemCount; builds the label for the item. The line, let itemPar equals MakeInputPar(labelText, min, max); is displayed to get the paragraph to be added. The line, containerElement.appendChild(itemPar); adds the paragraph to the container.

The function uses a for loop to generate each input paragraph in turn by calling the function makeInputPar. The end point of the loop is determined by the noOfItems parameter. The values of the min and max parameters are passed into the function makeInputPar. Let’s have a look at how this works.

Create an input paragraph

The program must build the HTML elements into which the user will enter the data. I’ve created this as a function so that we can use it anywhere we want to read a value from a user. Figure 8-3 shows the display that the input paragraph should produce. This reads in the sales for ice cream stand number 1.

The HTML that describes this input paragraph is shown below:

Click here to view code image

<p>
  <label class="menuLabel" for="s1SalesText">Stand 1 sales (0-10000):</label>
  <input class="menuInput" type="number" id="s1SalesText" value="0" min="0" max="10000">
</p>

The input paragraph is composed of a label element that contains the Stand 1 sales (0-10000) label and an input element to receive the data. The label and the input elements are assigned style classes to make it easy to manage their appearance. The input element has min and max attributes that are used by the browser to limit the values that the user can enter.

In our first version of this application, the input paragraphs were defined in the HTML file for the application. There were six such paragraphs, one for each of the ice cream stands. However, we can simplify the application by using JavaScript to make the input paragraphs.

A screenshot displays the source code to make the input paragraph using the makeInputPar function. The line, let inputPar equals document.createElement("p"); creates the enclosing paragraph. The line, let labelElement equals document.createElement("label"); creates the input label. The line labelElement.innerText equals labelText plus " ("plus min plus "hyphen" plus max plus "): "; adds the max and min to the label. The line, labelElement.ClassaName equals "menuLabel"; sets the style class for the label. The, line, LabelElement.SetAtribute("for", labelText); connects the input label; The line, inputElement.SetAttribute("max", max); sets the maximum value. The line, inputElement.SetAttribute("min", min); sets the minimum value. The line, inputElement.SetAttribute("value"); sets the initial value to 0. The line, inputElement.SetAttribute("type", "number"); sets the input type to the number. The line, inputElement.ClassName equals "menuInput"; sets the style class for the input. The line, The line, inputElement.SetAttribute("id", labelText); sets the Id to connect to the table. The line inputPar.appendchild(inputElement); adds the input to te enclosing paragraph.

The function makeInputPar uses the createElement function provided by the document object to create a paragraph element (inputPar) and give the paragraph two child elements. The children are a label element (labelElement) and an input element (inputElement). The makeInputPar function is supplied with three parameters:

The label to be used for the input

The maximum input value

The minimum input value

A program could make the input element for the first ice cream stand by making the following call:

Click here to view code image

var stand1input = makeInputPar("Sales 1", 0, 10000);

However, we are not going to do this because we are using a loop to create the inputs and add them to a container.

CODE ANALYSIS

Input generation

We can see this input generation in action by using the JavaScript console. We might also have some questions about it. Start by opening the application in the Ch08 Storing data\Ch08-04 Input Generation folder in the example code. This application contains an HTML page which has been generated by the doBuildSalesInputItems function. Open the Developer View by pressing F12.

Question: Can we look at the HTML that was generated by the doBuildSalesInputItems function?

Answer: Yes we can. If we click the Elements tab in the Developer View it will display a view of the document object. We can then open up the view to see the HTML for each element.

The screenshot displays the output page, and the source code of the ice cream sales program. The elements tab in the developer's view shows the source code of the ice cream sales application. The right pane of the screen displays the styles that are used in the application.

Question: Can we add another input element to the document from the console?

Answer: Yes, we can. Click the Console tab to open the console. First, we need a reference to the container element that holds the input paragraphs. Type in the following and press Enter:

Click here to view code image

> var containerElement =  document.getElementById('salesItems');

Next, we need to create a new input item. The function makeInputPar will do this for us. We will look at how this function works in the next section. Call the function to make a new input item called “New Sales” with a min of 1 and a max of 99:

Click here to view code image

> var newPar=makeInputPar("New Sales", 1, 99);

Now that we have our new paragraph, the next thing we do is add it to the children of the container element:

Click here to view code image

> containerElement.appendChild(newPar);

This adds our newly created paragraph to the page. You should see it appear. It will have the label “New Sales” and an input range of 1 to 99.

A snapshot shows the output of a code to add a new element. The left pane of the screen shows the ice cream sales list. The new element labeled as new sales is shown at the bottom. The right pane shows the console window where few lines of code are displayed.

Above, you can see the new element (with the caption “New Sales”) that has been added at the bottom of the list.

Question: How would I increase the number of ice cream stands?

Answer: Using a loop to generate the page makes it very easy to change the number of ice cream stands. If you take a look at the HTML code you will find the call of the function doBuildSalesInputItems. The final argument of this call is the number of stands to be created, which is presently six. If we want to handle 12 stands, we just have to change the HTML to reflect this. We don’t need to make any changes to the JavaScript program.

Click here to view code image

doBuildSalesInputItems('salesItems',0, 10000, 6);

Now we need to move on to how we can make a JavaScript program that can process the data that has been entered. To do that, we need to write some code to create a sales array from the contents of the input elements in the document.

Read back the values

In the previous version of the ice cream program, we had a separate statement that created an array element for each sales value. Below is the statement that got the sales for the initial two ice cream stands.

Click here to view code image

sales[0] = getNumberFromElement("s0SalesText");
sales[1] = getNumberFromElement("s1SalesText");

If the customer added more stands, we would then have to modify the program and add more statements. For 12 ice cream stands, we would need 12 of these statements. There is a better way to do this. We can use a loop to read the values from the HMTL elements. The loop will work through all the input paragraphs on the page. The input paragraphs are children of the sales item element.

Figure 8-4 shows how these elements are structured. On the left, we have the div element with the ID salesElements that contains all the elements. The div element contains six paragraphs, one for each ice cream stand. The first paragraph gets the input for ice cream stand 1. It contains a label and an input item. To get the user input, the program must work through the sales items and extract the data from the input element.

Figure 8-4 Input paragraphs

A set of code for a div element is displayed. The div element with the id sales Items has six paragraph elements inside. The first paragraph contains the label element and an input element. The label element includes the class and the input element includes the maximum and minimum values. The remaining five paragraph elements are simply written without any code inside the elements.

The program can use a for–of loop to work through the children and extract the value of each item. The code above shows how this works.

A sample code that illustrates the use of a for-of loop is presented. The first line of the code, var sales equals left square bracket right square bracket creates an empty array. The line var salesPos equals 0 start at the beginning of the array. The line var salesElement equals document.getElementById('salesItems') get a reference to the element containing the sales items. The line for (let item of salesElement.children) left brace is the start of the for-of loop that get the number from the input element. The line let salesValue equals getNumberFromElement(item.children[1]) inside the for-of loop get the number from the input element. The line sales[salesPos] equals salesValue store the number in the array. The line salesPos equals salesPos plus 1 move on to the next element in the array. After this line, the for-of loop ends indicated by a right brace.

CODE ANALYSIS

Reading numbers

Question: What is this code doing?

Answer: Good question. When the user presses the Calculate button, they have just typed in the sales values and want to see the total, highest, and lowest values displayed. The first thing the program needs to do is get the values out the input elements on the page and into the sales array. The input elements are children of the paragraphs that are themselves children of the salesItems element. Think of the salesItem element as a grandfather element. The grandfather has six children. These are the paragraphs that were generated when the page was built. Each of the six children has two more children, which are the label and the input elements.

A figure shows the salesItems element structure. A vertical rectangle on the left represents the salesItems element. The six paragraph elements of the salesItems element labeled as sales 1, sales 2, sales, 3, sales 4, sales 5, and sales 6 preceded by the paragraph tag is displayed on six rectangles arranged horizontally on the right. Six arrows from the salesItems element point to the six paragraph elements on the right. Sales 1 points to the two elements label and input on two rectangles on the right. Similarly, sales 2 points to another two elements label and input on two rectangles on the right.

The for–of loop will work through each of the child elements of the salesItems container. Each time around the loop, the variable item refers the next paragraph element in the salesItems. Each paragraph element contains two children: the label for the input and the input itself. The input element that we need is the second child of the sales paragraph, which will have index number 1 (because indexes always start at 0).

Click here to view code image

let salesValue = getNumberFromElement(item.children[1]);

This version of the getNumberFromElement function is supplied with a reference to the element it is reading, so it fetches the value input and returns the result as a number.

Question: What happens if the input element contains an invalid value?

Answer: The input element contains max and min attributes that are used by getNumberFromElement to validate the number that the user types in. If the number the user has entered is outside this range, or the user has not entered a number, the getNumberFromElement function returns a result of Not a Number (NaN).

Question: Would I have to change this code if we added more ice cream stands?

Answer: No. That’s the great thing about this loop. It will work through any number of input paragraphs.

MAKE SOMETHING HAPPEN

Use the debugger to see code run

You might be finding the code above a little hard to follow. You might be thinking that it would be wonderful to be able to watch it execute and see what each statement does. It turns out that you can do just that by using the debugger which is built into the Developer View in the browser. In this case we are not debugging the program because there’s something wrong with it; we just want to see how it works. Start by opening the application in the Ch08 Storing data\Ch08-04 Input Generation folder in the example code. This application contains an HTML page which has been generated by the doBuildSalesInputItems function. Enter some sales figures for the ice cream stands and then open the Developer View by pressing F12. Select the Sources tab in the Developer View.

A snapshot shows the sources tab. The left pane of the screen shows the ice cream sales list. The right pane of the screen is selected for the sources tab. The source files list is displayed on the left where the icecreamsales.js file is selected. The shortcuts for an open file, run command are shown at the center. Several options are displayed on the right. The options are as follows: watch, breakpoints, scope, call stack, XHR/fetch breakpoints, DOM breakpoints, global listeners, event listener breakpoints, and CSP violation breakpoints.

The Sources tab will show you all the files that make up the application. Note that the browser display that you see might not match the one above. I’ve changed the arrangement of the windows in the browser and zoomed in on the Developer View to make it clearer for the book. However, you can drag the window borders around to get a similar view.

We want to take a look at the JavaScript code which is in the file icecreamsales.js. Click this file name (it is highlighted in darker gray in the figure above).

A snapshot shows the sources tab. The left pane of the screen shows the ice cream sales list. The right pane of the screen is selected for the sources tab. The source files list is displayed on the left where the icecreamsales.js file is selected. The icecreamsales.js JavaScript code is displayed at the center. The code shows the function doCalc where a for-of loop is used to get the input. Several options are displayed on the right. The options are as follows: watch, breakpoints, scope, call stack, XHR/fetch breakpoints, DOM breakpoints, global listeners, event listener breakpoints, and CSP violation breakpoints.

The Sources view now shows us the JavaScript code in a window. Use the scroll bars to move down the code to find the doCalc function. This function is called from the HTML when the Calculate button is pressed. We are going to put a breakpoint at the first statement of this function. When the program reaches the breakpoint, it will “takes a break.” It will pause and we will be able to investigate what the function is doing and even run through the statements one at a time. We set a breakpoint by clicking just to the left of the line number in the listing.

The display will show a red dot at that position as shown above. Click to add a breakpoint. If you click in the wrong place, you can remove a breakpoint by clicking the red dot. Once you have set the breakpoint, click the Calculate button in the application to run the function. The browser will call the doCalc function and then pause when it hits the breakpoint.

A snapshot shows the sources tab. The left pane of the screen shows the ice cream sales list. At the bottom of the sales item, the calculate button is displayed. The right pane of the screen is selected for the sources tab. The source files list is displayed on the left where the icecreamsales.js file is selected. The icecreamsales.js JavaScript code is displayed at the center. The code shows the function doCalc where a for-of loop is used to get the input. Several options are displayed on the right. Between the scope and call stack option on the right, a set of local variables of the JavaScript code are displayed.

The program is paused at the statement where we set the breakpoint. You can see it highlighted in blue. We can use the transport controls to make the program run one statement at a time.

A screenshot of the transport controls is presented. The transport controls are shown at the top-right of the browser window. The transport control has seven control options where the step control option is located in the fifth position. A right arrow followed by a dot indicates the step control.

The transport controls look a bit like Egyptian hieroglyphics. They are in the top right-hand area of the screen in my browser, but they might be somewhere else on yours. We will find out more about each control as we go. For now, we want to use the Step control, which is indicated above. Click this, and the program will execute the indicated statement and then move on to the next one.

A snapshot shows the sources tab. The left pane of the screen shows the ice cream sales list. At the bottom of the sales item, the calculate button is displayed. The right pane of the screen is selected for the sources tab. The source files list is displayed on the left where the icecreamsales.js file is selected. The icecreamsales.js JavaScript code is displayed at the center. The line var sales equals an empty array is highlighted with a red dot on the left. After the click of the step control, the content of the sales array is displayed on the right of the code as sales equals an empty array.

Note that the content of the sales array is shown for you. If you press the Step button again you are shown the contents of the salePos variable. You can keep pressing the button (or use the function key F9) to step through the program. You can watch the program get a reference to the sales element and then enter the for loop, which will work through the elements. When the program calls the getElement function you will find that the view moves into that function and you step through the statements in that.

The JavaScript code for the getNumberFromElement function is displayed. The function includes the var text and var result. This var text gets the value as a string (text = "300") and the var result stores the number 300 as a value converted by the Number (text) function. The if condition inside the function checks for bad number input.

The getNumberFromElement function reads the text from an input element and converts it into a number. Here, you can see that the text is 300 as a string, and the result is 300 as a value. If you look back at the application you will find that the first sale value is 300.

You can use another transport button to step out of the getNumberFromElement function and return to where it was called.

A screenshot of the transport controls is presented. The transport controls are shown at the top-right of the browser window. The transport control has seven control options where the step out of current function control option is located in the fourth position. An up arrow above a dot indicates the step out of current function control.

When you have seen enough you can press the transport control that resumes normal program execution. If you leave the breakpoint set, you will find that if you press the Calculate button in the application, it will stop at the breakpoint the next time around.

A screenshot of the transport controls is presented. The transport controls are shown at the top-right of the browser window. The transport control has seven control options where the continue running control option is located in the first position. A vertical bar followed by a right arrowhead indicates the continue running control.

You can spend as much time as you like working through code. You can also use this technique to put breakpoints in any of the other sample programs and watch what they do, too.

Now that you know how the program works, you can make the change that adds two new ice cream stands to the system. The good news is that you only have to change the value 6 to the value 8 somewhere in the application. You can find my version in the examples in the Ch08 Storing data\Ch08-05 Eight Stand Version folder.

Your customer has had another idea. Rather than the application asking for the sales of Stand 1, she would like the application to show named locations, as shown in Figure 8-5.

Figure 8-5 Named stands

The ice creams sales application with named locations is presented. The title, ice cream sales is displayed at the top. The following sales locations are displayed vertically: Riverside Walk, City Plaza, Central Park, Zoo Entrance, Main Library, North Station, New Theatre, and Movie House. Each location has a minimum and maximum limit of 0 - 10000. The text field on the right of each location displays the value of 0. The calculate button is displayed at the bottom left.

Arrays as lookup tables

This looks like it might be quite hard to achieve, but it turns out that we can use arrays to help. In this case, we are going to use an array to hold a list of place names. When we first created an array, we used the following statement:

var newArray=[];

The characters [ and ] mark the start and end of the array that is being created. This statement creates an empty array, because there is nothing between the [ and the ]. We set the values into an array when we create it by putting values here:

var newArray=[1,2];

This statement creates an array called newArray that contains two numbers. The element at the start of the array contains the value 1, and the next element contains the value 2. This statement is exactly equivalent to these three:

var newArray=[];
newArray[0]=1;
newArray[1]=2;

We can also create arrays of strings. Consider the following statement:

Click here to view code image

var standNames = ['Riverside Walk','City Plaza','Central Park','Zoo Entrance',
    'Main Library','North Station','New Theatre','Movie House'];

This statement creates a variable called standNames that contains the names of all the stands. The item on the right of the assignment is the actual array. We can also use arrays like this in function calls:

Click here to view code image

doBuildSalesInputItems('salesItems',0, 10000,
  ['Riverside Walk', 'City Plaza', 'Central Park', 'Zoo Entrance',
  'Main Library','North Station','New Theatre','Movie House']);

This statement calls the function doBuildSalesItems. The final parameter to this call is an array that contains the names of all the ice cream stand locations. This version of the function can then use these names to build the HTML page:

The JavaScript code of the doBuildSalesInputItems function is displayed. The function contains four parameters containerElementID, min, max, and placeNames. The line var containerElement equals document.getElementByID(containerElementID) get the container that will hold the items. The for-of loop, for (placename of placeNames) left-brace work through the place names. The let itemPar equals makeInputPar(placename, min, max) create and input par. The line containerElement.appendChild(itemPar) add the input par to the children in the container. After this line, the for-of loop ends followed by the end of the function.

Rather than creating the name “Sales x,” where x is the number of the stand, this version of the function just works through the place names and feeds each name in turn into the makeInputPar function. The function doBuildSalesInputItems is called from the HTML when the page is loaded by the browser. The function call is triggered by the onload event:

Click here to view code image

<body onload="var standNames = doBuildSalesInputItems('salesItems',0, 10000,
  ['Riverside Walk', 'City Plaza', 'Central Park','Zoo Entrance',
    'Main Library','North Station','New Theatre','Movie House']);">

The text above comes from the HTML file for the application. The body element can contain an attribute called onload, which contains a string of JavaScript to be obeyed when the page is loaded by the browser. For this application, the string of JavaScript calls the doBuildInputSalesItems to create the input paragraphs for the sales values. You can find this function used in the example program in the Ch08 Storing data\Ch08-06 Named Stands folder.

CODE ANALYSIS

Creating named ice cream stands

This is all rather clever stuff. But you might have some questions:

Question: What is passed into a function when an array is used as an argument to a function?

Answer: The parameter in the function is a reference to the array. This means that if the function changes the contents of the array (by assigning something to a value in the array or by adding a new element on the end of the array), this will change the array because there is only ever one copy of the array itself. Consider this function:

Click here to view code image

function changeArrayElement(inputArray)
{
    inputArray[0]=99;
}

The function changeArrayElemenent has a single parameter, which is an array. It changes the value in the start of the array to 99.

var testArray = [0];

This statement creates an array called testArray, which contains a single element that is set to the value 0.

changeArrayElement(testArray);

This statement calls the changeArray method and gives it testArray as an argument. The question that we need to consider is: “What is the value in element 0 of testArray after the call of changeArrayElement?” The answer is that it contains 99 because the parameter to the function is a reference to the array. When the function runs, the reference is used to find the array and change the element in it. If you think about it, passing arrays by reference makes very good sense. Otherwise, a program would have to make a copy of an array to pass into a function call.

Question: How would I add another ice cream stand location to the application?

Answer: This application design means that to add another stand to the application, we just have to add the name of the new stand to the array value that is passed into the call of doBuildInputSalesItems. The JavaScript code does not have to be changed at all.

Question: Can an array hold numbers and strings in different elements?

Answer: Yes, it can. You can regard each element of an array as a totally separate variable that can hold any value. It can be confusing if you use arrays in this way, so in the next chapter, we will discover how to design variables that collections of items of different types.

Question: What is the maximum size of an array?

Answer: An array can be very, very large. There is a limit, which will be determined by the amount of memory inside the computer running JavaScript. Modern computers have huge amounts of memory, so it is really unlikely that your program will ever have a problem with array size being too large.

Creating fixed width layouts

If you run the program in the Ch08 Storing data\Ch08-06 Named Stands folder, you will notice that it works perfectly well, but the layout of the input elements is not very consistent, as you can see in Figure 8-6.

Figure 8-6 Poor layout

The ice creams sales application with named locations is presented. The title, ice cream sales is displayed at the top. The following sales locations are displayed vertically: Riverside Walk, City Plaza, Central Park, Zoo Entrance, Main Library, North Station, New Theatre, and Movie House. The calculate button is displayed at the bottom left. Each location has a minimum and maximum limit of 0 - 10000. The text field on the right of each location displays the value of 0. The text fields are misaligned such that some extend on the right and some end earlier.

The input elements are not lined up vertically because the names of the different locations are of different lengths. This is not a programming problem, so we don’t need to make changes to the JavaScript, but it would be useful to be able to modify the style of the labels for each item so that they are the same size.

The CSS text above is the definition of the menuLabel style class, which is used to style the menu label (hence the name). I’ve added two new attributes to the style definition. The first tells the browser that this element is a block that should be displayed inline with enclosing elements. The second item sets the width of the element to 12 characters. If we make these changes to the style sheet, the input display matches what the customer requested in Figure 8-6. You can find this version of the application in the Ch08 Storing data\Ch08-07 Named Stands fixed width example folder.

MAKE SOMETHING HAPPEN

Highlight the best and worst sales locations

Your customer (who, by now, has given you a lot of ice cream) has one final request. She would like the program to highlight the best and worst sales locations in the display. She would like the highest sales to be highlighted yellow and the lowest to be highlighted in blue.

Hint: to do this the program must make a second pass through the sales elements after it has determined the highest and lowest values. Any sales elements with a sales value that matches the highest can be assigned a yellow style class. Any sales elements with a sales value that matches the lowest can be assigned a blue style class. This is the best way to do it because it is possible to have several sales values that are the highest or the lowest. You can find my version in the examples in the folder Ch08 Storing data\Ch08-08 Highlight High and Low.

Interactive Multiplication Tables Tester

The multiplication table tester application is displayed. The multiplication table for 13 is presented. The labels are as follows: such as 1 times 13 is, 2 times 13 is, 3 times 13 is, 4 times 13 is, 5 times 13 is, and 6 times 13 is. A text field is shown at the right of each label with the respective value. The last text field is differentiated from the others. The label, which multiplication table do you want is shown with the value of 13 in the corresponding text field. The label, how many lines do you want is shown below with the value of 6 in the corresponding text field. The buttons make the multiplication table and check the multiplication table is displayed on the bottom left and right respectively.

We can use our new skills to improve the multiplication table tester application that we created in Chapter 6. The version above generates a multiplication table for any value and then checks what the user enters. You can find the working application in the Ch08 Storing data\Ch08-08 Multiplication Table Tester example folder.

It has been suggested that the program could be improved if it displayed the scores at the end:

To make this work, you have to add a new paragraph to the HTML to display the result and then work through the program to find out where the table is scored. Have a go yourself and then take a look at my version in the Ch08 Storing data\Ch08-09 Multiplication Table Tester with scores example folder.

What you have learned

In this chapter, you discovered how a program can use arrays to store large amounts of data. You’ve also built on your knowledge of how a JavaScript program can generate document elements and display them.

A variable can be declared as an array and acts as a container for multiple values. Each value in an array is stored in an element, and a particular element can be identified by an index value. An index is sometimes called a subscript.

Elements in an array with a particular index value are created when a value is assigned to that element. There is no need to specify the size of an array when it is created.

An array value exposes a length property that gives the number of elements in the array.

Element index values start at 0 and extend up to the value of (length-1). This range of index values is called the bounds of the array. There is no element with an index value of the length of the array.

If a program uses an index value outside the bounds of the array, a value of undefined is returned.

A program can use the for–of loop construction to work through the elements in an array. A program can also work through elements of an array by creating a variable that counts through the index values in the array.

An array with a number of elements can be created using a single statement.

Inputs in an HTML document can be assigned label elements that display a prompt for that input.

The Developer Console in the browser can be used to step through JavaScript programs and view the contents of variables held in them.

Here are some questions that you might like to ponder about the use of functions in programs:

How do I find out the size of an array?

An array variable provides a property called length, which contains the number of elements in the array.

Does every element in an array have to be the same kind of data?

No. An array can contain numbers, strings, and references to other objects.

Do I have to put a value into every element?

No. For example, you could create an element with index 0 and another element with index 5. All the elements in the middle (meaning those with index values 1, 2, 3, and 4) would be set to undefined.

Can I store a table of data as an array?

A JavaScript array has only one dimension—the length of the array. You can think of it as a row. Some programming languages allow you to create “two-dimensional arrays.” You can think of these as a grid with width and height. JavaScript does not allow you to create two-dimensional arrays. However, you could create a table data structure by creating an array that has an array as each element.

What happens to my program if I used an index value outside the range of the array?

If the program is storing data in this location, the array will be extended to hold the value at the new index. If the program is reading data from this location, the array access will return the value undefined.

Can I use indexes on other data items?

Yes. You can use an index to obtain the individual characters in a string.

What happens if I don’t initialize the elements in a new array?

Any elements that you don’t initialize are set to the undefined value.

What happens if I add two arrays together using the + operator?

It would be nice if adding two arrays together created a long array with one set of elements appended to the other. Unfortunately, this does not happen. Instead Java JavaScript creates the string version of each array and then appends one string to the other. However, JavaScript array objects provide a concat method that can be used to concatenate (add) an array onto the end of another.

Can I use an image as a label for an input item?

Yes, you can. The content of a label can be an image or some text and an image.

What is the difference between the children of an HTML element and a JavaScript array?

They are implemented in slightly different ways, but you can use an index to access values in each, and they both expose a length property. You can also use the for–of loop construction to work through the elements in either.

Can I use an array to allow a function to return more than one value?

What a good question. Yes, a program can return an array, which can contain multiple values. However, the function and the caller would have to agree on what was in each of the array elements. In the next chapter, we will discover a much neater way of creating objects that contain named data items.

Can I use the JavaScript debugger to debug the JavaScript in any web page?

Yes. If you press F12 when viewing your favorite web page, you can then open up the JavaScript files and take a look at them.

9
Objects

An animated picture shows a coffee shop where a man stands inside. Few snack items are placed inside a glass box. A coffee maker is shown behind the man. Some coffee cups are placed inside the shop. Two customers are shown having a cup of coffee placed on a table each. One of the customers uses a laptop while the other uses a mobile.

What you will learn

Programs can work with many different types of data, including integers, floating-point numbers, and strings of text. They can also create arrays of a particular data type. However, the data that programs need to work with is often more complex than single values. In this chapter, you’ll learn how to use objects to store related data items. You will discover how software can create custom objects, and you will have your first go at solving a real computing problem.

Make a tiny contacts app

Create an object

Investigate local storage

Use JSON to encode object data

Working with JSON

Use property accessors

Investigating property accessors

Use a data schema

Create your own data storage

Improving the user interface

Improving data storage

What you have learned

Make a tiny contacts app

Suppose one of your friends is a lawyer who wants someone to create a personal contacts app. The client wants a tiny, “lightweight” application to provide a quick way of storing contact details—names, addresses, and telephone numbers—for her important clients. You sit down with her and decide how the application will work:

Figure 9-1 shows how the application will look. It has three text boxes for data entry and two buttons. When the Save Contact button is pressed, the data entered into the text boxes is stored. To find a contact, the user enters the name and then presses the Find Contact button. The program then searches the contact store for a contact with that name. If the contact is found, the program displays the address and phone number information. If the contact is not found, the program displays an alert, as shown in Figure 9-2.

Figure 9-1 Tiny Contacts prototype

The tiny contacts application is presented. The title of tiny contacts is displayed on the top. Three text boxes are displayed for entering the name, address, and phone number respectively. The text boxes have the following values: Rob Miles, 18 Pussycat mews London NE14 10S, and plus 44 (1234) 56789 respectively. Two buttons find contact and save contact are displayed at the bottom.

Figure 9-2 Contact not found

The tiny contacts application is presented. The title of tiny contacts is displayed on the top. Three text boxes are displayed for entering the name, address, and phone number respectively. The text box of the name has the value of Fred Bloggs. Two buttons find contact and save contact are displayed at the bottom. The alert box that shows the message, the page says not found with an ok button is displayed at the top.

Prototype HTML

The best way to show the lawyer what her program will look like is to create a prototype that behaves in the same way as the finished product. We can do this by creating an HTML page and then adding just enough JavaScript to allow us to demonstrate how the program will be used.

An HTML code is presented. The link element inside the head element, link rel = "style sheet" href = "styles.css" creates the link for the style sheet. The script element inside the head element, script src = "tinycontacts.js" adds the javascript program for the application. The button class elements inside a paragraph element, call the functions doFind and doSave to find and save a contact respectively.

This is the HTML for the prototype application. It defines the three input areas and the two buttons. There is one new element on this page—the textarea element.

The textarea element

If you look at Figure 9-1, you will see that the address of a contact can be entered as multiple lines of text. We can’t use an input element to read multi-line text because an input element only supports a single line. A textarea is configured by two attributes called rows and cols, which define the size of the data entry area on the screen. The Tiny Contacts application uses an area that has 5 rows and 40 columns.

Click here to view code image

<textarea class="inputTextarea" rows="5" cols="40" id="address"></textarea>

The textarea will display a scroll bar if the user enters more than five lines of text, and a textarea will automatically wrap text if the user types off the end of the line. A JavaScript program can use the value property of a textarea to interact with the content of the text area.

Prototype style sheet

The HTML file contains the elements that make up the application display. The CSS (Cascading Style Sheet) file controls how the display will look. Your customer would like a clean black and white display, so you propose this style sheet:

A style sheet code is presented. The style of menuHeading includes the font size, font family, color, and text-shadow. The line text-shadow: 3 px 3 px blue, 10 px 10 px 10 px grey represents the style class for the application heading. The font family, font size, and color inside the inputLabel, inputText, inputTextarea, and menuButton is applied to all the text style classes. The inputlabel settings are applied only to the label style classes.

The CSS file defines a style for the heading. It then contains settings shared by all the other text styles in the document, followed by settings, which are only applied to the labels. This makes it easy to change the font, size, or color of all of the text. It also makes it possible for a designer to change the style of any element on the page without changing the HTML file at all.

Prototype JavaScript

The third component of the tiny contacts application is the JavaScript that provides the behaviors. The prototype application doesn’t do much. It just displays contact information if the user searches for “Rob Miles” and displays Contact not found if the user searches for any other name. The Save Contact button just displays an alert when it is pressed.

The JavaScript code is presented. The function displayElementValue displays the text in the element with the specified ID and it includes two parameters id and text. The function getElementValue with the parameter id gets the data value from the element with the specified ID. The function doSave saves the contact details. The function doFind finds a contact. The line of code inside the function doFind, var name equals getElementValue("name") gets the name value. The if condition statement inside the doFind function, if (name double equals "Rob Miles") is the name "Rob Miles".

You can find the prototype application in the Ch09 Objects\Ch09-01 Tiny Contacts Prototype sample folder. You can use it to enter and search for contact information. The application will only display output if you search for a contact named “Rob Miles,” and it doesn’t store any entered data. However, it’s very useful for demonstrating how the application will work. Your client agrees that the application can work like this and says you can start building it.

Helper functions

If you look closely at the prototype JavaScript code, you’ll notice a pair of tiny functions. I’ve written these to help move data between the HTML page and the application:

The JavaScript code is displayed. The function displayElementValue with the parameters id and text is displayed. The line of code, var element equals document.getElementByID(id) gets the element being changed. The line of code, element.value equals text sets the value in the element. The function getElementValue with the parameter id is displayed below. The line of code, var element equals document.getElementByID(id) gets the element being read. The line of code, return element.value returns the value in the element.

The function displayElementValue accepts two arguments: the id of the element and the text to be displayed. It is used to display values on the HTML page. The call of the function below would display the phone number text on the page. Note that although the phone number is described as a number, the data itself is a string of text.

Click here to view code image

displayElementValue("phoneText", "+44(1234) 56789")

The function getElementValue accepts a single argument: the id of the input element to be read. The call of the function below would get the name that had been entered into the HTML page and store it in a variable called name.

Click here to view code image

var name = getElementValue("name");

You might wonder why I wrote such small functions. They don’t make the program much smaller. If I were to write the application without these functions, it would only add a few statements. However, I think they do make the program much clearer because the functions express exactly what is being done without the distraction of how they work. For example, consider the function that is called when contact information is not found. At the time the function is called, we can tell from the name of the function exactly what the program is doing.

Click here to view code image

function displayContactNotFound()
{
    alert("Not found");
}

Another advantage of using a function like this is that it makes it easy to change what the program does when a contact is not found. If the customer says that she would like a sound to be produced when the item is not found, we can just add this to the displayContactNotFound function without having to work through the entire program to find the code that deals with finding contacts.

Storing contact details

Now that the customer has agreed how the program should work and we have built the HTML page and style sheet files, we can start to create the code. However, before we can write the code to save a contact, we need to decide how the contact information will be stored. There will be lots of contacts. When we wrote the ice cream sales application, we used an array to hold the sales information. One way to store the contact details would be to use three arrays: one for the name, one for the address, and third for the phone number:

Click here to view code image

var contactNames = [];
var contactAddresses = [];
var contactPhones = [];

The data for a contact would be held in array elements with a particular index value. In other words, contactNames[0] would hold the name of the contact at the start of the storage, contactAddresses[0] would hold the address, and contactPhones[0] would hold the phone number. Figure 9-3 shows how this works.

Figure 9-3 Array storage

A figure displays the structure of array storage. Three rows (data arrays) of four square blocks (array index values) each are displayed. The three rows represent the name, address, and phone. The four blocks from left to right represent the indexes 0, 1, 2, and 3 respectively. The name, address, and phone of the array index 0 are Rob Miles, 18 Pussycat Views, and (1234) 567 567 respectively. The name, address, and phone of the array index 1 are Fred Bloggs, 1 Forthe Road, and (1234) 556 767 respectively. The name, address, and phone of the array index 2 are Joe Smith, House of Joe, and (1234) 367 547 respectively. The name, address, and phone of the array index 3 are Imogen Bloggs, Immy Villas, and (1234) 723 523 respectively.

The elements at index 0 in each array hold the details for Rob Miles. We can use the elements at a given index to build up a set of contact information for a specific person. For example, Imogen Bloggs lives at Immy Villas and has a phone number of (1234) 723523. We can write a function that stores a contact at a particular index position in all the arrays:

The JavaScript code for the function storeContact is presented. The function storeContact has a parameter pos. The line of code inside the function, contactName[pos] equals getElementValue("name") stores the name. The line of code inside the function, contactAddress[pos] equals getElementValue("address") stores the address. The line of code inside the function, contactPhones[pos] equals getElementValue("phone") stores the phone number.

The function storeContact accepts an argument that gives the position in the array. This is where the contact will be stored. In other words, if the value of the argument is 0 the contact will be stored at the start of the storage.

Each statement in the function fetches data from an element on the HTML page and stores it at the given index in the array that holds the data for that type of data. Remember that a JavaScript program automatically creates an array element at the specified index when the program stores a value in that element. The first contact will be stored at the element with index 0 (remember that arrays are indexed from 0). The next will be stored at index 1 and so on. The statement below saves contact information on the HTML page into the elements at the start of the array.

storeContact(0);

Finding contacts

Now that we know how to store contact information, the next thing we can work on is finding it. The customer wants to be able to search for contacts by name. We need something that works through the stored contacts and finds the position of the one we want to display. In other words, if asked to find the entry for “Joe Smith” in the contact store shown in Figure 9-3, it would return the value 2.

The JavaScript code of the function findContact is presented. The function findContact has a parameter name. A for loop is written inside the function. The line of code, for (let pos equals 0; pos less than contactNames.length; pos equals pos plus 1) count through the array elements. The if condition statement, if(contactNames[pos] double equals name) check if the stored name matches the parameter. The line, return pos returns the index value if the name matches. The line, return NaN after the for loop ends returns not a number (NaN) if the name was not found.

The findContactPos returns the position in the array of the contact with the name supplied as a parameter. It uses a for loop to work through the contactNames array, comparing each element in the array with the name it is searching for.

CODE ANALYSIS

The findContacts function

The findContacts function is a very important part of the application. You might have some questions about it.

Question: What does the for loop do?

Answer: The function must look at each element in the contactNames array to see if it matches the name the function is searching for. If I asked you to search through a row of pigeonholes to find the one with my name on it, you’d start at the first pigeonhole, check its name, and then move on to the next one if there was no match. The for loop controls the contents of a variable called pos (an abbreviation for “position”). The value of pos starts at 0, and the loop ends when the value in pos reaches the length of the array.

Question: What would happen if the contactNames array is empty when the findContacts function is called?

Answer: The loop only runs as long as the value of pos is less than the length of the array. An empty array has a length of 0. The initial value of pos is set to 0 when the loop is set up. This means that the loop is never performed if the array is empty because 0 is not less than 0.

Question: What happens when a match is found for the name being searched?

Answer: When the program finds a matching name, the value of the index variable is returned to the caller. This is the position in the array of the name.

Click here to view code image

var pos = findContactPos("Fred Bloggs");

For example, using the data store in Figure 9-3, the above statement would create a variable called pos, which would be set to 1 by the call of findContactPos.

Question: What does the findContactPos function do if the name is not found in the contactNames array?

Answer: If the name is not found in the array, the for loop will complete without finding a match. The program would then move on to the statement after the for loop, which returns the value Not a Number (NaN) to indicate that the name was not found. It is perfectly sensible for a function to contain more than one return statement. Note that it is up to the program calling findContactPos to check to see if the name was found.

This type of search behavior is common in systems that you use every day. Whenever you use a credit card to pay for something, the bank’s computer will use the credit card number to search for your bank account information so that the transaction can be authorized and added to your statement.

Displaying contacts

The final function that we need is one that displays the contact on the HTML page. This function is given a position in the contacts store and displays the elements in each array at that position. It uses the displayElementValue function that we saw earlier to display each item:

Click here to view code image

function displayContact(pos){
    displayElementValue("name", contactNames[pos]);
    displayElementValue("address", contactAddresses[pos]);
    displayElementValue("phone", contactPhones[pos]);
}

Saving a contact

The final pieces of code that we need are the functions that respond to the button presses in the application. When the user clicks the Save Contact button, the function doSave is called by the browser. This function must work in two different ways:

It must create a new contact store for a new contact.

It must update the contact information for an existing contact.

The doSave function gets the contact name from the web page and then uses the findContactPos function to see if the contact store already contains someone with that name. The findContactPos returns a value, which is stored in a variable called pos. If the value of pos that is returned is not a number (NaN), the function sets the value of pos to the length of the array, so that the contact information will be stored at the end of the array. Otherwise, the newly saved data will overwrite the existing data. I’ve added some comments to this code to make it clear what each section is doing.

Click here to view code image

function doSave() {

    // get the name of the contact being saved
    var name = getElementValue("name");

    // find the position of the name to save
    var pos = findContactPos(name);

    if(isNaN(pos)){
        // if we didn't find an existing contact name
        // we store the contact on the end of the array
        pos = contactNames.length;
    }

    storeContact(pos);
}

CODE ANALYSIS

The doSave function

The doSave function implements the editing behavior of the application. You might have some questions about it.

Question: Why does the findContactPos function sometimes return NaN?

Answer: We know that the JavaScript language provides a variable value called “not a number” or NaN. This is used by JavaScript itself. If we ask the JavaScript Number function to convert the string Fred into a numeric value, it will return NaN. In the Tiny Contacts application, I’m using the value NaN in the findContactPos function to indicate that a position could not be found. If I asked you to search through a row of pigeonholes to find the one with my name on it, and you couldn’t find it, you’d say: “Sorry, Rob. I can’t find it.” The value NaN is how findContactPos indicates that it couldn’t find what it had been asked to look for. I could have used a different flag value if I wanted, such as -1 (which would not be meaningful as an index into an array). This form of notification relies on the user of a function checking the reply of the function. Later in this book, we will look at ways that a program can explicitly stop running by raising an exception when things go wrong.

Question: What does the function use the length of the contactNames array for?

Answer: If the findContactPos function indicates that it can’t find a contact with that name (which it does by returning NaN), this means that the store does not contain a contact with this name. The contact information must be stored in a new location. When the program is first run, the length of the array is 0, so the first contact will be stored at element 0, which is the start of the array; the next contact will be stored at element 1 (because the length of the array is now 1); and so on.

Question: What happens if the user changes the name of a contact and then saves it?

Answer: This is a very good question. It points to a potential bug in the application. We can answer the question by working through the code with an example. If the user opens a contact called “Rob,” changes the name to “Rob Miles,” and then presses the Save Contact button, what will the doSave function do? The function will fail to find a contact with the name “Rob Miles,” and then it will create a new contact with that name. This could be dangerous because there would now be two contact entries for the same contact. If the user searches for the old name by mistake, they might see data that is out of date.

This kind of issue crops up frequently when software is being created. As you write the program code, you discover questions that you didn’t consider when you discussed the design of the application. The only way to resolve this issue is to ask the customer what she wants to happen. She says that she will never need to change the name of a contact, so she is okay with the program being left as it is.

Finding a contact

The doFind function runs when the user clicks the Find Contact button. It can use the findContactPos function to search for a contact with a name that matches the one entered. If a contact is found, the contact contents are displayed. If a contact is not found, the function must display a message:

Click here to view code image

function doFind() {

    var name = getElementValue("name");

    var pos = findContactPos(name);

    if(isNaN(pos)){
        displayContactNotFound();
    }
    else{
        displayContact(pos);
    }
}

You can find the complete application in the Ch09 Objects\Ch09-02 Array Tiny Contacts folder. If you try it, you will discover that it works fine. You can enter contact details, save them, and search for them.

Use an object to store contact details

As you’ve seen, we can create a perfectly workable Tiny Contacts application by using a list for each piece of information we want to store for our contact. However, working with data stored in this way is not as easy as we might like. If we ever add a new data item for a contact (perhaps we want to add their email address), we would need to add a new list and then make sure that items in it were managed correctly.

We want a way of holding all the information about a contact in one place. We need some kind of “container” that can hold the name, address, phone number, and any other items we want to store. One possible solution might be to use an array to store information about each customer, but this wouldn’t make it very easy to access specific detail items. Instead, we’ll use a JavaScript object.

You’ll hear a lot about objects over the next few chapters, as they are one of the fundamental building blocks that underpin the language. You might have heard the term “object-oriented programming.” Now you are going to find out what an object is and how to use it in a JavaScript program.

MAKE SOMETHING HAPPEN

Create an object

We can start our description of objects by making some using the JavaScript console in the browser. Open the example application in the Ch09 Objects\Ch09-03 Object Tiny Contacts examples folder and press F12 to open the Developer View. Select the Console tab in the view.

In JavaScript, we can create an empty object by using a pair of open and close braces ({}). Type in the statement below and press Enter. Do not use a pair of brackets ([ and ])—they are for creating arrays.

> var contact = {};

The process of creating an object does not return a value, so when you press Enter, you will see a familiar undefined message:

> var contact = {};
<- undefined

As usual with the JavaScript console, you can view the contents of a variable simply by typing the name of the variable. Type in contact and press Enter:

> contact

JavaScript shows you that the contact object does not contain any properties.

> contact
<- {}

Let’s add a name property to the contact object. Type in the statement below, which sets the name property of the contact object to the string Rob Miles. Press Enter.

> contact.name = "Rob Miles";

This is an assignment operation (that’s what the = means); an assignment expression always returns the value being assigned, so JavaScript replies with the string “Rob Miles”.

> contact.name = "Rob Miles";
<- "Rob Miles"

Let’s take a look at what has changed in the object. Type in contact and press Enter to view the contents of the contact object:

> contact

The contact object contains one property which is the name of the contact.

> contact
<- {name: "Rob Miles"}

We can add a second property to the contact by setting an address property in exactly the same way as we added the name. Type in the statement below and press Enter.

> contact.address = "18 Pussycat Mews";

The address is added to the contact, and the console shows us the value assigned as before.

Click here to view code image

> contact.address = "18 Pussycat Mews";
<- "18 Pussycat Mews"

Type in the statement below to view the contact, and press Enter to see what has been added to the contact.

> contact

The contact object now contains a name and address. We could keep adding properties to match the requirements of our application.

Click here to view code image

> contact
<- {name: "Rob Miles", address = "18 Pussycat Mews}

Objects are managed by reference. In other words, the contact variable we have created refers to a location in computer memory where the contact object is stored. We can create a new variable and set it to refer to the same location as the contact variable. Type the statement below, which creates a variable called refDemo, which refers to the same object as contact. Press Enter when you’ve typed in the statement.

> var refDemo = contact;

Creating a new variable always returns a result of undefined, which the console will now show us.

> var refDemo = contact;
<- undefined

Now let’s take a look at the object that refDemo refers to. Type in refDemo and press Enter to get the console to display the object that refDemo refers to.

> refDemo

Because refDemo refers to the same object as contact you will see the same properties displayed.

Click here to view code image

> refDemo
<- {name: "Rob Miles", address = "18 Pussycat Mews}

The refDemo variable refers to the same object as contact. We can prove this. Enter the following statement and press Enter:

> refDemo.name = "Rob Bloggs"

This statement changes the name property of the object referred to by refDemo. As with other assignments, it displays the value being assigned.

> refDemo.name = "Rob Bloggs";
<- "Rob Bloggs"

Now, view the contents of the contact variable by typing its name and pressing Enter:

> contact

Both contact and refDemo refer to the same object, so changes made via refDemo will also change the object that contact refers to.

Click here to view code image

> contact
<- {name: "Rob Bloggs", address = "18 Pussycat Mews}

The name property is now Rob Bloggs. This change was not made via the contact reference; instead, it was made via the refDemo reference.

Use an object in the Tiny Contacts program

We can use an object to simplify the Tiny Contacts program. The program now only needs a single array to hold all the contact information.

var contactStore = [];

Each of the objects in the contactStore array will have a set of properties that are the stored data for that contact. To make this work, we will have to modify some of the functions in our program. Rather than storing the different parts of contact data in individual arrays, the storeContact function now adds the elements as properties, which are added to a contact object:

The JavaScript code for the function storeContact is presented. The function storeContact has a parameter pos. The line of code inside the function, var contract equals left brace right brace creates an empty object. The line of code, contact.name equals getElementValue("name") adds the name. The line of code inside the function, contact.address equals getElementValue("address") adds the address. The line of code inside the function, contact.phone equals getElementValue("phone") adds the phone number. The line of code, contactStore[pos] equals contact stores the contact in the array.

The displayContact function now displays the properties in a contact object rather than elements from the three arrays that store contact data.

Click here to view code image

function displayContact(pos){
    var contact = contactStore[pos];
    displayElementValue("name", contact.name);
    displayElementValue("address", contact.address);
    displayElementValue("phone", contact.phone);
}

The example program in the Ch09 Objects\Ch09-03 Object Tiny Contacts folder contains a version of the Tiny Contacts program that uses an object rather than separate arrays. If you take a careful look at the JavaScript code, you will discover that some of the functions are completely unchanged.

Store data in JavaScript local storage

The Tiny Contacts program works perfectly well except for one thing. There is no way of persisting the contacts data. Each time the user opens the page, it starts with an empty set of contacts. For the Tiny Contacts program to be properly useful it needs a way of storing data. Some computer languages can save and load data in the file storage on the system they are running on. A JavaScript program running inside a browser is not usually allowed to interact with files stored on the host computer. JavaScript programs are often part of pages downloaded from anywhere on the Internet, and it would be very dangerous to give these programs access to files on your computer. However, JavaScript does provide local storage. This is managed by the browser, and our JavaScript applications can use it to store reasonable amounts of data.

You can think of local storage as a data object that is persisted by the browser on the host computer. This means that every machine has its own copy of local storage. Fortunately, our customer only has one computer, a laptop that is used for everything, so this is not a problem. Later in this book, we’ll discover how we can use network storage to store data.

Each browser program has its own implementation of local storage, which means that items stored when using the Edge browser would not be accessible when using the Chrome browser. The browser maintains an object called LocalStorage, which has methods that are used to save items in local storage and get them back.

MAKE SOMETHING HAPPEN

Investigate local storage

The example program in the Ch09 Objects\Ch09-04 Local Storage Tiny Contacts folder uses local storage to store contact information. Let’s find out how it works. Open the application in your browser.

The tiny contacts application is presented on a browser screen. The title of tiny contacts is displayed on the top. Three text boxes are displayed for entering the name, address, and phone number respectively. Two buttons find contact and save contact are displayed at the bottom. The alert box that shows the message, this page says empty contact store created with an ok button is displayed at the top.

The first time the contacts page is opened, there will be no contacts store. The page displays an alert to indicate this. Click OK in the alert to clear it and press the F12 key to open the Developer View. Now move to the Console tab so that you can enter some JavaScript. Programs use local storage by placing strings of text in named locations. The method to store an item in local storage is called setItem. Type the statement below and press Enter.

Click here to view code image

> localStorage.setItem("test", "This is some test data we are storing");

When you press Enter, the method setItem will run and store the string This is some test data we are storing at the location test. The setItem method returns the value undefined.

Click here to view code image

> localStorage.setItem("test", "This is some test data we are storing");
<- undefined

We can use the method getItem to view the contents of an item stored in local storage. Type in the statement below.

Click here to view code image

> localStorage.getItem("test");

When you press Enter, the getItem method will run and return the contents of that location.

Click here to view code image

> localStorage.getItem("test");
<- "This is some test data we are storing"

The content of location test will still be there if we return to this web page after having shut down the browser. It will even be present after we have rebooted our computer. We can see how the data storage for our Tiny Contacts application works. Type some contact details into the application and press the Save Contact button. The contact information is held in a location called TinyContactsStore. Type in the following statement to read the contents of this location.

Click here to view code image

> localStorage.getItem("TinyContactsStore");

When you press Enter, you will see the contents of the contacts store now contains the data that was entered.

The tiny contacts application is presented on a browser screen. The left pane of the screen shows the following. The title of tiny contacts is displayed on the top. Three text boxes are displayed for entering the name, address, and phone number respectively. The text boxes have the following values: Rob Miles, 18 Pussycat mews London NE14 10S, and plus 44 (1234) 56789 respectively. Two buttons find contact and save contact are displayed at the bottom. The right pane of the screen shows the console window where the JavaScript code of the local storage is displayed.

If you store some more contacts, you will find that they are added to the stored item. If you restart your PC and then load the same application, you will find that the contact information has been retained.

The functions setItem and getItem can be used to store and retrieve data in local storage. If you want to remove the contents of a local storage, the removeItem function can be used to remove an item. The statement below would remove the TinyContactsStore item from the browser storage.

Click here to view code image

localStorage.removeItem("TinyContactsStore");

Use JSON to encode object data

Now it is time to discover how JavaScript programs can store data as formatted text. This is one of the most powerful features of the language, and it underpins many JavaScript applications that store and transfer data around the Internet. It also makes it possible for JavaScript applications to exchange data with applications written using other programming languages. The technology is called JSON—JavaScript Object Notation. In the previous “Make Something Happen,” we saw that the contacts store for our application is retained as a string of text. This text is encoded using JSON.

Click here to view code image

[{"name":"Rob Miles","address":"18 Pussycat Mews\nLondon\nNE14 10S","phone":"+44(1234) 56789"}]

The JSON string above represents a contact store that contains a single contact. If you look at it carefully, you can see some strings that are the names of properties (for example, phone) and some strings that are values (for example, +44(1234) 56789). The string above actually creates an array (which is why the outer characters are square brackets—[ and ]). The array contains a single object (which is the element enclosed in braces—{ and }) inside the array.

MAKE SOMETHING HAPPEN

Working with JSON

You should still have your browser open at the example program in the Ch09 Objects\Ch09-04 Local Storage Tiny Contacts folder. If you haven’t, open the application, press F12 to open Developer View, and select the Console tab. We can start by making an object and adding some properties to it. Type the following statement and press Enter:

Click here to view code image

> var contact = {name: "Rob", address: "Rob's House", phone: "1234"};

This is a quick way of creating JavaScript objects that we have not seen before. Rather than creating an empty object, we have populated a new object with three properties. Each property is given as the name of the property, followed by a colon (:) and the value for that property. Successive properties are separated by the comma (,) character. We now have a variable called contact, which contains my details. If we just type the name of the variable, the console will show us the contents:

Click here to view code image

> contact
<- {name: "Rob", address: "Rob's House", phone: "1234"}

The console is showing us the JavaScript representation of the contact object. We can convert the object into a JSON string by using the stringify method provided by the JSON object. Type the following statement and press Enter:

Click here to view code image

> var jsonContact = JSON.stringify(contact);
<- undefined

The stringify method acts on a JavaScript object and returns a string of JSON text that describes it. The variable jsonContact now contains a JSON formatted string that represents the contents of contact. Type in jsonContact and press Enter to view it:

Click here to view code image

> jsonContact
<- "{"name":"Rob","address":"Robs House","phone":"1234"}"

The JSON string version of an object looks very like the JavaScript representation, with the difference that the names of properties are also enclosed in double quotes ("). Another method, called parse, can be used to convert this string back into an object:

Click here to view code image

> var decodedContact = JSON.parse(jsonContact)
<- undefined

We now have a new variable called decodedContact, which contains the contact information that was stored in the string jsonContact. We can view this by just entering the name of the variable:

Click here to view code image

> decodedContact
<- "{"name":"Rob","address":"Robs House","phone":"1234"}"

So, in this Make Something Happen, we have “round tripped” a contact object. We have converted it into a string of text by using the wonderfully named stringify method, and we have converted the string back into an object by using the parse method.

We can combine local storage and JSON to make two methods that will save and load the contacts in the Tiny Contacts application.

The JavaScript code is presented. The line, var contactStore equals left bracket right bracket is an array that holds the contacts. The line, var storeName is a constant variable that holds the name in local storage. The function saveContactStore save the contacts. The line inside the function, var storeJson equals JSON.stringify(contactStore) stores the string in local storage. The function loadContactStore loads the contacts. The line inside the function, var dataString equals localStorage.getItem(storeName) gets the string from local storage.

The JavaScript code for JSON parsing is presented. The if condition statement is displayed as follows: if (dataString double equals null), contactStore equals an empty array, and return false. Then, contactStore equals JSON.parse(dataString) and return true.

The loadContactStore function is called when the page is first loaded. The saveContactStore function is called each time a contact is saved. The name of the local storage item to be used to store the contact data is held in a variable called storeName. The value in this variable is set when the application is started.

Click here to view code image

function doStartTinyContacts(storeNameToUse){
    storeName = storeNameToUse;

    if(!loadContactStore()){
        alert("Empty contact store created");
    }
}

The function doStartTinyContacts is called to start the contacts store and load the contact values. If the load fails, the function displays an alert to indicate that the program has made an empty contact store. The HTML page for the application calls the doStartTinyContacts function when the page is loaded.

Click here to view code image

<body onload='doStartTinyContacts("TinyContactsStore");'>

The string "TinyContactsStore" is given as an argument to the call of doStartTinyContacts from within the web page. This makes it easy for us to change the location of the stored data. You can find this code in the example application in the Ch09 Objects\Ch09-04 Local Storage Tiny Contacts samples folder.

CODE ANALYSIS

Using JSON

JSON makes it much easier to move data between JavaScript applications and also to store data in the form of strings. But you might have some questions about it:

Question: Where is the JSON standard defined?

Answer: One of the great things about JSON is that it is human readable. You can see how property names and values go together. If you want to see the standard that defines what a JSON document can contain, you can find it at https://www.json.org/.

Question: What types of data can a JSON document store?

Answer: A JSON document can hold strings of text (which are enclosed in quote characters), numeric values, and the logical values true and false.

Question: How long can a JSON string be?

Answer: Strings in JavaScript can extend to many thousands of characters, so you can use JSON to store large objects if required.

Question: What happens if I store a reference in the JSON string?

Answer: The reference is followed and the contents of the object are inserted into the JSON. We’ve seen this in action already. The contactStore in the Tiny Contacts application is an array of references to objects. When it is converted into objects, each reference is followed, and the object contents are inserted into the string.

Question: What happens if a program tries to store an invalid value like Not a Number (NaN) in a JSON string?

Answer: We’ve seen that JavaScript variables can hold values such as Not an Number (NaN) or infinity. These values are stored in a JSON string as the special value null, which is used in JSON to indicate that a value is missing.

Question: What happens if the program tries to parse a string that does not contain valid JSON text?

Answer: The JSON.parse method expects to be given a string of JSON to work on. If the parse method can’t decode the string, it does something we haven’t seen before. It throws an exception and ends the execution of the program. Exceptions are a way of forcing a program to respond to an error. We will discuss them in the next chapter.

Use property accessors

This section has perhaps the most confusing heading in the whole book. JavaScript programs can use property accessors to work with the properties in an object. Before we talk about property accessors, let’s refresh our understanding of what a property is.

Click here to view code image

var contact = {};
contact.phone  = "+44(1234) 56789";

A JavaScript program can create an empty object and then add properties to it. The two statements above create a contact object and adds a phone property to the object. The new property is the string "+44(1234) 56789". We have seen that programs can add properties to an object. The object acts as a container for the property values that have been added to it. We can identify these properties in the program by name as you can see above, where we create a property called phone. This method is called dot notation because the name of the property is given after a dot (.) in the program text.

A property accessor looks a lot like an array indexer. It is called bracket notation because the property identifier is enclosed in square brackets. It works a bit like an array, except that the item used as an index can be any value. This makes a JavaScript object behave like a dictionary. One of my favorite jokes is to tell someone that the word “gullible” is not in the dictionary and then watch as they look up the word and proudly read it out to me. A dictionary lets you look up definitions starting from a given word. If you look up the word “gullible,” you will get a result along the lines of “easily persuaded to believe something.” In JavaScript, if you look up a property accessor, you get the value of the property with the specified name:

The JavaScript code for the creation of an empty object is presented. The line, var contact equals left brace right brace creates an empty object. The line, contact["phone"] equals "plus 44 (1234) 56789" adds a phone property to the object using a property accessor.

The statements above show this works. The first statement creates an empty object called contact. The second statement adds a property “phone” to the empty object by using a property accessor. Note that the property accessor is the string “phone.” This is a very powerful feature of JSON, but it can also be a confusing one, particularly when you try to compare JavaScript objects with JavaScript arrays. Let’s see if we can’t make things clearer.

MAKE SOMETHING HAPPEN

Investigating property accessors

Open the application in the example folder Ch09 Objects\Ch09-05 Universal Tiny Contacts. It is a contact manager that works in the same way as previous ones. Press F12 to open Developer View and select the Console tab. First, we want to investigate property accessors. Let’s start by making an empty contact. Type the following statement and press Enter:

> var contact = {};

Creating a new variable does not return a value, so the console displays the familiar message undefined.

> var contact = {};
<- undefined

We now have an object called contact, which has no properties. We can view the contents of contact by entering its name and pressing Enter:

> contact

JavaScript will tell us that the contact object is empty by printing a pair of curly brackets with nothing between them.

> contact
<- {}

Now, let’s add a name property to the contact object. Enter the following and press Enter:

> contact.name = "Rob";

This statement returns the value being assigned, so the console prints the value "Rob".

> contact.name = "Rob";
<- "Rob"

The contact object now contains a property called name, which contains the value "Rob". Now let’s add another property, but this time, we will refer to the property using a property accessor. Type in the statement below and press Enter.

Click here to view code image

> contact.["address"] = "House of Rob"

This statement adds a property called address, which is set to the value "House of Rob". It also displays the value being assigned, as usual.

Click here to view code image

> contact.["address"] = "House of Rob"
<- "House of Rob"

If we look at the contents of the contact object, we will see both of these properties. Type in the statement below and press Enter to take another look at the contents of the contact object:

> contact

The contact object now contains name and address properties.

Click here to view code image

> contact
<- {name: "Rob", address: "House of Rob"}

At this point, you might start to think that a property accessor makes every object look like an array. Let’s see what happens if we try to use an object in the same way we would an array. The following statement tries to store the string "Hello world" at element 0 of an array. Let’s try to do that with the contact object. Type in the statement below and press Enter.

> contact[0] = "Hello world";

JavaScript does not produce an error message, so the statement must have done something. The value "Hello world" has now been added as a property of the contact object.

Click here to view code image

> contact[0] = "Hello world";
<- "Hello world"

Let’s take a look at the contents of the contact object. Type in the object name and press Enter:

> contact

This is very confusing. The contact object now has a property called 0, which contains the string "Hello world".

Click here to view code image

> contact
<- 0: "Hello world", name: "Rob", address: "House of Rob"}

The next thing to do is to try and use 0 as a property identifier in our program. The statement below is trying to access a property called 0. Type it in and press Enter to see what it does:

> contact.0

JavaScript will not let you use a number as an object property identifier, so this will generate an error:

Click here to view code image

> contact.0
VM142:1 Uncaught SyntaxError: Unexpected number

Property identifiers in a program must obey the same rules that are applied to all JavaScript identifiers. However, we can still access this property by using 0 as a property accessor. Type this statement and press Enter to prove this:

> contact[0]

You have correctly identified a property and so JavaScript shows you the value it holds:

> contact[0]
<- "Hello world"

Please remember that I am in no way recommending that you should use anything other than strings of text as property accessors. As with lots of things in life, just because you can do something does not mean that you should try to do it.

We have discovered that we can use strings of text as property accessors rather than putting property names in the program code. This is interesting, but at the moment, we are not sure why it is so useful. It turns out that property accessors give us a lot of power. Our programs can be made to create their own object designs. Consider these two statements:

Click here to view code image

var propertyName = "phone";
contact[propertyName]  = "+44(1234) 56789";

The first statement creates a variable called propertyName that contains the word "phone" as a string of text. The second statement uses the contents of propertyName as property accessor. The effect of these statements would be to change the phone property of the contact variable. If I want to create an object with a particular set of properties, I can now do this from within the program, rather than having to create the code by hand. Why is this useful? Because it is how we can create a schema that describes the design of an object and then use that schema to create the objects themselves.

Use a data schema

Your Tiny Contacts program is becoming quite popular. A friend has seen you working on it and would like you to create a program to keep track of his video game high scores. Another friend wants a program to store her recipes. In fact, there are lots of people who seem to be looking for simple data stores. You could create all these different programs by editing the Tiny Contacts application, modifying the HTML elements, and then changing the JavaScript code to match. However, this is looks like it might be hard work.

A much better way forward would be to build something that describes the data storage needed by each application. Programmers call this a schema. The schema for the Tiny Contacts application would include name, address, and telephone items for each contact. The schema for a video game high score application would include video game name, high score, date, and time items for each high score. The schema would be designed at the start of the project. Then when the program runs, it can create the data storage objects by using property accessors that are described in the schema.

PROGRAMMER’S POINT

Design the system before you build it

If you were making an airplane, you would make sure you had a design before you started putting the wings on. The same is true with a software project. It is vital that you consider what data is to be stored and how it fits together before you start to write any code.

A large software system will contain many different components. At the start of the design process, a programmer will focus on identifying the components and how they are related. For example, a banking application would contain customers, accounts, addresses, statements, and transactions. The first part of the design process would be deciding the relationships between these components in the system. For the bank, we might decide that a customer can have multiple accounts but only one home address. At this point, we are working at a high level of abstraction. You can think of abstraction as a way of “stepping back” from the problem you are trying to solve and trying to think about the “bigger picture” surrounding the code that you are writing.

As soon as we had a high-level design, we would work with the customer to make sure that the design can be made to do what they want. Then we would move on to creating schemas for each of the components, making sure to check with the customer that each component holds the data that is required.

We are trying to avoid a situation right at the end of the project when the customer asks something like, “Where do you hold the date of each transaction?” If we had created the software as soon as we thought we knew what was needed, this might be the first time we’ve heard of this requirement, and it would need a lot of work to add it to the finished system.

JavaScript property accessors let us create data objects that describe the data items that are to be stored. These can then be used by the application to create objects that will hold the data. We’ve already done this kind of thing in the multiplication table and ice cream sales applications, where an application creates the HTML page that will be used to enter data. Now we are extending this process to allow an application to create bespoke objects to hold data. If you look in the HTML page of the Ch09 Objects\Ch09-05 Universal Tiny Contacts application, you will find a call of a function—doBuildPage.

Build HTML from a schema

The doBuildPage function takes two arguments. The first argument is the name of the display element on the HTML page that is to contain all the HTML that will be generated to provide the user interface. We’ve used this technique before in the ice cream sales application, where the program generates the input fields for all the ice cream stands.

The HTML code for the doBuildPage function is presented. The line, doBuildPage("contactItems" is a container object on the web page for the HTML. The line, id:"name", prompt:"Name", type:"input" is the description for the name entry. The line, id:"address", prompt:"Address", type:"text area" rows:"3", cols:"40" is the description for the address entry. The line, id:"phone", prompt:"Phone", type:"input" is the description for the phone entry.

The second argument is an array of objects, each of which describes one of the items to be stored. The schema above is for the Tiny Contacts application, and it defines three data items—the name, address, and phone number items. All the descriptions contain at least three property values:

The id to be used to identify the property in the object that will store a contact.

The prompt gives the text that is to be displayed in the HTML when this property is being edited.

The type gives the type of the item. There are two types of property. An input type uses the input HTML element to read a single line of text. The textarea type uses a text area. For a textarea, the description also contains row and col values to specify the size of the text area to be used.

The doBuildPage function works through each of the items in the schema and creates an HTML element for each item. This is then added to the container element to build the display. This function is called when the page is loaded.

Click here to view code image

function doBuildPage(containerElementID, schema){

    // store the schema for use later by the application
    dataSchema = schema;

    // get a reference to the element containing the edit items
    var containerElement = document.getElementById(containerElementID);

    // work through each of the items in the schema
    for (item of dataSchema) {
        // make an element for that item
        let itemElement = makeElement(item);
        // add the element to the container
        containerElement.appendChild(itemElement);
    }
}

The doBuildPage function uses a function called makeElement to make each HTML element for display on the page. This function uses the description from the schema to decide which what kind of element to make.

Click here to view code image

function makeElement(description) {
    // Create the enclosing paragraph
    var inputPar = document.createElement("p");

    // Create the label for the element
    var labelElement = document.createElement("label");
    labelElement.innerText = description.prompt + ":";
    labelElement.className = "inputLabel";
    labelElement.setAttribute("for", description.id);
    inputPar.appendChild(labelElement);

    // decide what kind of element to make
    switch (description.type) {
        case "input":
            inputElement = document.createElement("input");
            inputElement.className="inputText";
            break;

        case "textarea":
            inputElement = document.createElement("textarea");
            inputElement.className = "inputTextarea";
            inputElement.setAttribute("rows", description.rows);
            inputElement.setAttribute("cols", description.cols);
            break;
        // add new kinds of element here
    }

    // set the id for the element
    inputElement.setAttribute("id", description.id);
    // give the element an initial value
    inputElement.setAttribute("value", "");
    // add the element to the paragraph
    inputPar.appendChild(inputElement);
    // return the whole paragraph
    return inputPar;
}

The code in makeElement is very similar to the code in the function makeInputPar that we created in the “Create an input paragraph” section in Chapter 8. It creates an HTML paragraph that contains a label and an input element. The function is supplied with an object that describes the kind of input that is required. The object contains the three properties of id, type, and prompt that we saw earlier. These are used to build the HTML display.

Build a data object from a schema

When the user presses the Save Contact button, the storeData function is used to read data from the HTML elements on the page and create properties in a new data object that is then stored.

Click here to view code image

function storeData(pos){
    // Create an empty data item
    var newData = {};

    // Work through the data schema
    for(property of dataSchema){
        // Get the data out of the HTML element
        let itemData = getElementValue(property.id);
        // Create a property to store that data
        newData[property.id] = itemData;
    }
    // put the new data in the storage array
    dataStore[pos]=newData;

    // save the data store
    saveDataStore();
}

The schema array holds the application together. It describes each of the data items to be displayed by the editor and it is used to build the HTML page and also to create each data object for storage. We can extend the schema design by adding new types of data input, perhaps a number input type.

MAKE SOMETHING HAPPEN

Create your own data storage

In this Make Something Happen, I want you to investigate some working programs and try to produce your own schema for a data store. The example application in the Ch09 Objects\Ch09-05 Universal Tiny Contacts folder holds a tiny contacts data manager that uses the schema above. The example application in the Ch09 Objects\Ch09-06 Recipe Store folder holds a recipe storage program. Both programs use the same JavaScript and style sheet files. The only file that is changed for each application is the HTML file that contains the schema for the application. Take a look at both these applications and use what you find out to create a third application that can store video game scores. The items to be stored are:

The name of the video game

The high score reached

The time in minutes that the game lasted

A details panel that can accept 5 lines of text that are 40 columns wide

You should be able to achieve this by only changing the contents of the HTML file. If you get stuck, you can take a look at my version, which you can find in Ch09 Objects\Ch09-07 Game Scores.

Improving the user interface

We now have a working data store, but it is not very easy to use. When searching for an item, the user must enter an exact match for the item name for it to be found. If they mistype a letter of the name, perhaps by typing “rob” rather than “Rob,” the name will not be matched. These problems are caused by the simple nature of the function that finds items in the data store:

The JavaScript code for the function findDataPos is presented. The function has a parameter name. A for loop is written inside the function for storing the name. The if condition statement inside the for loop, if(storedName double equals name) is a very simple test for a name match.

We can make the find process much easier by making the test ignore whether the text was typed in UPPERCASE or lowercase. This can be achieved by converting the search string and all the items it is searching for to lowercase before performing the test:

Click here to view code image

function findDataPos(name) {
    name=name.toLowerCase();
    for(let pos=0;pos<dataStore.length;pos=pos+1){
        let storedName=dataStore[pos].name;
        storeName = storedName.toLowerCase();
        if(storedName==name) {
            return pos;
        }
    }
    return NaN;
}

The version of Tiny Contacts in the Ch09 Objects\Ch09-08 Tiny Contacts Improved Search example folder uses this version of the function.

Add “Super Search” to Tiny Contacts

You show the improved search to your lawyer customer and she is very pleased. However, after a while, she comes to see you, saying that she has had an awesome idea to make the application even better. She doesn’t like having to type in the entire name to search for a contact. Instead, she wants to type in just the first part of the name and then use the Find Contact button to step through all the contacts that start with that part. For example, she might type just the letter “R,” and then repeated presses of the Find Contact button would find the entries for “Rob”, “Ronald,” and “Rita.” She calls this her “Super Search” feature, and she would really like you to add it to the Tiny Contacts program.

PROGRAMMER’S POINT

User ideas are often the best kinds of ideas

Making a great application is only the first step in making a successful one. You also have to work hard to engage with your users and make them into your sales force. We have seen that one way to do this is to always respond constructively to error reports. Another good technique is to engage with users and encourage them to suggest improvements. This is a win-win proposition. They get a solution tailored to their needs, and you get another feature that you can use to sell your solution.

Solve a problem

Making Super Search work is an interesting problem. I suppose you could call it our first “proper” programming problem. By that, I mean that it is not obvious how we can solve it. With all the other applications we have created, we have been automating a behavior that we know how to do. We knew how to calculate multiplication tables and add up ice cream sales before we went anywhere near a computer. But for this problem, we don’t know how to do what is being requested. So the best possible answer we can give our lawyer friend is that we will think about it and get back to her later.

The first step toward solving a problem is to determine whether the problem can be solved. Trying to do the impossible never ends well. In this case, I can tell you that I’ve used systems that work in a similar way to that suggested by the lawyer, so it is possible. So with that useful knowledge, let’s work out how we can solve the problem. The first step to solving the problem is to write down the sequence of actions that need to be performed to use the action in the application:

Type part of the name into the name input. (for example, “R”).

Press the Find Contact button. The first contact (meaning the one nearest the start of the contactStore array) with a name that starts with R will be displayed.

If the user presses Find Contact again, the next contact with a name that starts with R will be displayed.

If the user enters a new name, the Find behavior resets, and the Find Contact button now searches for the new name.

After thinking about it, I found three things that the application needs to be able to do to make these behaviors work:

The application needs to be able to test whether one string starts with the search string. This is so it can match the contact with the name “Rob” to the search string “R.”

The application needs to store the search string and the search position it has reached in the connectStore array. This needs to happen because when the user presses Find Contact, the application knows what to search for and where to start the search from.

The application needs to know when the user types in a new name. This needs to happen because when the name changes, the application can reload the search string and restart the search at the start of the data array.

Find out if one string starts with another

The JavaScript string object provides a method called startsWith that returns true if the string starts with another string.

Click here to view code image

var name="Rob";
if(name.startsWith("R")){
    alert("Rob starts with R!")
}

The JavaScript code above shows how this works. So now we know that we can search the contacts for names that start with a string, and then we can move on to the next problem. The program needs to store the current search string and the position it has reached in the array of contacts.

Retain the find string and find position

These two variables hold the string we are finding, as well as the current find position. They are global variables that are declared outside any function so that they are visible to all the functions in the application.

var findString = "";
var findPos = 0;

We start by setting the find string (findString) to an empty string ("") and the find position (findPos) to 0. This means that if the user presses the Find Contact button as soon as the application has been started, the search will match all the contacts (all names start with an empty string) and search from the start of the contact store. (Remember, arrays are indexed from 0.)

When the user presses the Find Contact button, the doFind function is called to search. We can make this function start searching with the find string at the current find position:

The JavaScript code for the function doFind is presented. The line, var pos equals findStartsWithDataPos(findString, findPos) searches for a contact. The if statement, if(isNan(pos)) check if a match is found. The function displayDataNotFound inside the doFind function displays a message if no contacts match the search.

This doFind function uses a function called findStartsWithDataPos, which is given the current findString (perhaps the string “R”) and the current value of findPos (perhaps the position 0). If findStartsWithDataPos doesn’t find a match, it returns Not a Number (NaN), and the displayDataNotFound function is called to tell the user about this.

The findStartsWithDataPos function is provided with a name to search for and a start position. It searches for a contact that has a name that starts with the search string. It starts the search at the supplied start position.

The JavaScript code for the function findStartsWithDataPos is presented. The function has two parameters name and startPos. The line, name equals name.toLowerCase() converts the name to lowercase. The for loop, for (let pos equals startPos; pos less than datastore.length; pos equals pos plus 1) starts the search at the search position. The line, let storedName equals datastore[pos].name gets the name out of the search contact. The line, var lowerCaseStoredName equals storeName.toLowerCase() converts the name to lower case. The if statement, if (lowerCaseStoredName.startsWith(name)) checks for a match. The line, return pos returns the search result. The line, return Nan if the search fails return this.

Our application can use these two functions to search through the datastore array for contacts that start with a particular string. Each time doFind is called, it will use findStartsWithDataPos to find the next contact to display. The final piece of the solution is code that restarts the search each time the user changes the contents of the name input field.

Detect changes to the name input

This is perhaps the easiest part of the solution. We have seen that HTML elements can be made to call JavaScript functions when something happens in the document. We’ve used the onload attribute to specify a JavaScript function to be called when an HTML document is loaded into the browser. HTML provides an oninput function that will call a JavaScript function when the user inputs text into an input field. We can use this to specify a method to run when the user changes the name of a contact when using the application:

Click here to view code image

<input class="inputText" oninput="resetFind();" id="name" value="">

This is a very powerful feature. If you’ve ever used a web page that automatically updates or checks your text as you type it in, you now know how it works. The resetFind function sets up a new search:

The JavaScript code for the function resetFInd is presented. The line nameString equals getElementValue("name") inside the function gets the name from the HTML input element. The line findString equals nameString.trim() inside the function removes the leading and trailing spaces. The line findPos equals 0 inside the function sets the find position to the start of the array.

The resetFind function gets the name element from the HTML document and then uses a JavaScript string feature that we’ve not seen before. The trim function returns a version of the string that has had all its leading and trailing spaces removed. It would convert “R” to “R.” This is very useful. The user will become confused if a search for “Rob” doesn’t find “Rob,” and this prevents that problem from happening. The value of findString is then set to this trimmed value, and findPos is set to 0 to make the next search start at the beginning of the stored contacts.

CODE ANALYSIS

Investigating Super Search

The Super Search version of Tiny Contacts is in the Ch09 Objects\Ch09-09 Tiny Contacts Super Search examples folder. Let’s open it and take a look inside. Open the application in your browser and press F12 to open the Developer View of the application.

Question: Does it work?

Answer: Good question. Try it. Enter some data, save it, enter the first letter of one of the names into the name field, and press Find Contact. The application will display the first match and continue to display matches up to the end of the data.

Question: What happens if I enter an empty name to search for?

Answer: Try it. The behavior of the startsWith function means that all strings start with an empty string. So the findStartsWithDataPos function will match every contact. The user of the Tiny Contacts program will really like this, as it provides them with a way of stepping through all the saved contacts.

Question: How does the application add the oninput behavior to the name input field?

Answer: Changes to the name input field must be detected and used to update the search string. If you use the Elements tab in the Developer View to take a look at the web page HTML, you will see that the oninput attribute has been added to the name input field. However, it has not been added to the address underneath. How does this work?

The tiny contacts application is presented on a browser screen. The left pane of the screen shows the following. The title of tiny contacts is displayed on the top. Three text boxes are displayed for entering the name, address, and phone number respectively. Two buttons find contact and save contact are displayed at the bottom. The right pane of the screen shows the elements window where the elements of the HTML code are displayed.

I’ve made a tiny change to the function that generates the HTML for each data item that needs to be stored. The makeElement function regards the element, which has the id name as special. When it generates that element, it adds the attribute to it. Open the Sources tab in the Developer View and take a look in the tinyData.js file.

The tiny contacts application is presented on a browser screen. The left pane of the screen shows the following. The title of tiny contacts is displayed on the top. Three text boxes are displayed for entering the name, address, and phone number respectively. Two buttons find contact and save contact are displayed at the bottom. The right pane of the screen shows the sources window where the tinydata.js source code is presented. The tinydata.js file is selected on the left.

The statement that I have highlighted tests the id of the element being created and adds the oninput attribute if it is the name element.

Question: How hard would it be to add this feature to the Recipe and Video Game Score applications?

Answer: The wonderful thing about the way that our solution works is that such a change would require no programming effort at all. We simply have to update the versions of tinydata.js with the Super Search version.

MAKE SOMETHING HAPPEN

Improving data storage

At this point, your lawyer friend has lots of ideas about how the application could be made better. She even suggests some kind of partnership where she takes a stake in the business and gets a share of any income that you get from selling the application. This sounds reasonable to you because it is always useful to have a good lawyer on your side when you are writing software. Here are a few of the ideas that she would like you to add.

She would like to add an “email” input so that the program can keep track of the email address of each contact.

She would like a button that clears the HTML form to make it easy to enter new contacts.

She would like the search to “wrap around,” so that when she searches through to the end of the list, she then returns to searching at the start.

See if you can make these features work. If you need ideas, you can take a look at my solution, which you can find in the Ch09 Objects\Ch09-10 Super Tiny Contacts examples folder.

As a further exercise, you might like to make a datastore application that can hold data that you would like to store.

What you have learned

In this chapter, you learned how JavaScript objects allow programs to store related items as properties of a single object and how to make programs that work with objects.

An object can contain any number of named property values. Each property value can be regarded as a variable holding a particular kind of value. An object can contain numbers, text, and references to other objects.

A program can create an empty object using a pair of braces with nothing between them—{}.

A populated object (one with properties) is created if the braces enclose a comma-separated list of property values. Each property value is expressed as the name of the property followed by a colon and the property value. For example, you could create the following implausible object: {name:"Rob Miles",age:21}. This object contains two properties called name and age.

Objects are managed by reference. A variable can contain a reference to an object. A single object can have multiple reference variables referring to it. An object can contain a property that is a reference to another object. This allows a program to build data structures such as lists.

An object reference can be given as an argument to a function call and then passed into the function as a parameter of that function. This allows the function to interact with the properties in the object and to add additional properties to the object.

A program can store a large amount of structured data by using an array of object references.

The browser maintains a local storage area for each different website the user visits. Values placed in local storage are maintained when the browser is not running, and the host machine is switched off. The values that are stored are strings of text. Each string is accessed by using a string that gives the item a name.

JavaScript Object Notation is a standard for encoding JavaScript variables into strings of text. The JSON object provides a stringify method to convert a variable into a JSON string and a parse method to convert JSON strings into variables.

There are two ways that a program can access a property. Dot notation uses a dot to separate the object variable name and the property name (contact.name). Bracket notation uses a property accessor (usually a string) enclosed in square brackets (contact["name"]).

A data schema is an object that contains a design for other objects. Schemas can be used in association with bracket notation property accessors (see above) to allow a program to dynamically create custom software objects.

JavaScript provides functions to convert text in a string to uppercase and lowercase (toLowerCase and toUpperCase) and also to remove leading and trailing spaces (trim).

JavaScript provides a startsWith function that can be used to detect whether one string stars with another.

A JavaScript function can be made to run when the user of an application changes the text inside an input element in the document. This is achieved using the onchanged attribute of the input or textarea element.

Here are some questions that you might like to ponder regarding the things you have learned in this chapter:

What is the difference between a textarea element and an input element in HTML?

Both elements have a value attribute that can be used by a JavaScript to read and write their contents. A textarea can be made to span an area of the HTML document to allow multiple lines of text to be entered. The textarea element can be given rows and cols attributes that specify the size of the area on the page.

How does a textarea represent multiple lines of text?

When the value attribute of a textarea is read by a JavaScript program the browser separates each line using the line feed character. We first saw line feed in Chapter 4 in the “Escape sequences in strings” section. The line feed character can be used in a string to mark the end of a line of text in the string. The textarea also uses line feed characters to arrange the display of any text loaded into it. The textarea will also break text and display scroll bars as appropriate to make the text fit on the screen.

Can I add a property to any JavaScript variable?

No. JavaScript will not complain if your program tries to do this, but properties added to variables containing Boolean values, strings, or numbers are not stored with the variable. If you want to add properties to an object, you need to tell JavaScript that your program is creating an object by using the {} notation.

Can I use an object as an argument to a function call?

Yes. We have done this many times in our programs already. The argument is passed as a reference to the object.

What happens if an object in memory has no variable referring to it?

Good question. As a program runs, variables that refer to an object could be reassigned to refer to different objects. In addition, variables defined using let and var may be discarded as program execution moves in and out of blocks of code. This can lead to objects in memory that no longer have any variables that refer to them. The browser that is running the JavaScript program also runs a special process called the “garbage collector,” which searches for objects that have no references and reclaims the memory used by them. This is an automatic process as far as our programs are concerned, although we should be careful not to write code that create and discard large numbers of objects, so that our applications are not slowed down by the garbage collector having to come in and clean up all the time.

Does a browser only keep one local storage area on a given machine?

A browser keeps one local storage area per web connection origin. Two websites on the same host will be on the same origin, so the sites https://robmiles.com/blog and https://robmiles.com/javascript would share the same local storage. JavaScript programs running from pages stored on a particular PC will all share the same local storage on that PC.

How do property accessors really work?

A property accessor uses an accessor value to get the name of a property on an object. For example contact["name"] would access the name property of an object referred to by the variable contact. A program can also use other value types to access a property of an object. For example, contact[99] would also access a property (using a number as an accessor) as would contact[true] (using a Boolean value as an accessor). JavaScript manages this by converting the property to a string and then using this to search the properties of the object. However, you should not use anything other than a string as a property accessor. Just because something is possible does not mean that you should do it.

Can I use a reference as a property accessor?

This would be legal JavaScript, but it would be a very dangerous thing to do because when JavaScript converts the reference to a string (see above), it gets the same string for all object references.

What happens if a program uses an accessor value that does not exist?

If JavaScript can’t find a property with a particular accessor name, it returns the value undefined.

What is the difference between [] and {}?

A pair of square brackets creates an empty array object. A pair of braces (curly brackets) creates an empty object. Arrays can use indexers to access array elements. and JavaScript will automatically create array elements as a program populates the array. Objects use property accessors to access properties.

Can I use a variable to identify the property to be accessed?

Yes, you can. If the program creates a string variable that contains the name of the property, a program can use the string contents as a property accessor.

Can I use a single object to store all the tiny contacts by using the name of a contact as a property accessor?

Good question. We could write something like contacts["Rob Miles"] = robMilesContact. This would make a “Rob Miles” property of the contacts object that contains a reference to robMilesContact. This would remove the need to have an array of contacts, but it would also make for strange behavior because the name of the contact would be used to locate it in the contact store. If the name property of the contact were changed, we would have to make sure that the name property was also changed. Otherwise, the user would find it difficult to locate the contact. I try to make sure that I store a single piece of data in one place only, rather than having two pieces of linked data elements that have to be kept synchronized. A better idea would be to assign each contact a unique number that we can use to index them in the contact store.

Part 3
Useful JavaScript

In the final part, we take our JavaScript knowledge to the next level, starting by picking up some new design skills and using them to build a complete “business worthy” application. Then we move on to investigate the popular node.js platform and use it to create a JavaScript web server. Next, we will write some applications that can consume network services. And we’ll round off the book by having some serious fun with a look at game creation in JavaScript. We start by drawing simple graphics and then move on to create a complete game with computer-controlled artificial intelligence (AI) opponents.

10
Advanced JavaScript

What you will learn

In this chapter, we are going to take our JavaScript knowledge to the next level. We are going to discover how applications manage errors with exceptions and how to design data storage with classes. We’ll discover how class inheritance can save us time when creating applications and how we can use object-oriented techniques to make data components that can look after themselves. We’ll be doing this by creating a fully featured data storage application you could use to run a business.

Manage errors with exceptions

Breaking JSON

Class design

Manage Imogen’s Fashions

Investigate using super to create instances

Investigate the getDescription method

Expand the fashion shop

What you have learned

Manage errors with exceptions

In Chapter 9, when we were looking at JSON, we discovered that JSON uses exceptions to signal when things go wrong. An exception is an object that describes something bad that has just happened. A piece of JavaScript can raise or throw an exception to interrupt a running program. Now is the time to find out what this means and discover the part that exceptions play in creating reliable applications.

If you remember, JSON (JavaScript Object Notation) is a standard for encoding the contents of JavaScript variables into text so that they can be stored or transferred to another machine. We used JSON to convert the Tiny Contacts store into a string so that it could be stored using local storage in the browser. The JSON object provides methods called stringify and parse that can move JavaScript objects to and from text strings.

Click here to view code image

var test = {};
test.name = "Rob Miles";
test.age = 21;
var JSONstring = JSON.stringify(test);

The statements above create a JavaScript object called test, which contains name and age properties. The contents of this object are then converted into a string called JSONstring by the stringify method.

{"name":"Rob", "age":21}

This is the string that would be stored in JSONstring. This string can be converted back into a JavaScript object by using the JSON parse method:

Click here to view code image

var test = JSON.parse(jsonString);

MAKE SOMETHING HAPPEN

Breaking JSON

The stringify and parse methods will fail if they are given invalid inputs. They fail by raising or throwing an exception. Let’s investigate what this means and how programs can be made to handle this failure. Use your browser to open the example application in the Ch10 Advanced JavaScript\Ch10-01 JSON Validator examples folder.

A screenshot is displayed with the title that reads "JSON Validator." The application allows the user to enter the string input and check if it contain valid JSON. The string {"name": "Rob", "age": 21} is entered in the input field. When the parse button is clicked, it displays the output as : "valid JSON."

This application tests strings of text to find out if they contain valid JSON. It works by handing exceptions thrown by the JSON parse method. When the Parse button is pressed, the application reads the string from the input and displays whether the string contains valid JSON. Look back through Chapter 9 to find some valid JSON to use to test it. Try it with a few strings to prove that it works.

Now press F12 to open the Developer View and select the Console tab so that we can investigate the application. The JSON parse method fails by throwing an exception. Let’s see what that means. Type in the following statement, which attempts to parse a string with the dangerous sounding contents kaboom. Press Enter to see what happens.

> JSON.parse("kaboom");

The JSON parse method is not able to make sense of kaboom, and it indicates this by throwing an exception. We have not included code to catch the exception, so the JavaScript console displays an error message in red:

Click here to view code image

> JSON.parse("kaboom");
Uncaught SyntaxError: Unexpected token k in JSON at position 0
    at JSON.parse (<anonymous>)
    at <anonymous>:1:6

We are not used to JavaScript programs complaining in the event of an error in the program code. If our program combines values incorrectly, JavaScript will use the values Not a Number (NaN), undefined, or overflow to indicate that something has gone wrong. Our program must test for these values to decide whether an action has worked properly.

The error created by parse is called an exception. It denotes the fact that the requested action can’t be performed. If the exception is not caught, the sequence of execution will end. Statements that might throw an exception can be placed inside a try block of code. The try block is followed by a catch block, which contains statements to be performed if an exception is thrown. This is called a try-catch construction. Let’s type one in. Enter the code below, remembering to press Enter at the end of every line.

Click here to view code image

> try {
    JSON.parse("kaboom");
} catch {
    console.log("bad json");
}

When you press Enter after the closing curly bracket of the catch block, the JavaScript code runs. The parse method will fail and throw an exception, but this time the exception is thrown inside a try block, and the associated catch clause will run and log a message on the console:

Click here to view code image

> try {
    JSON.parse("kaboom");
} catch {
    console.log("bad json");
}
bad json

Enter the same construction replacing the word kaboom with some valid JSON, such as {}. Note that this time, the bad json message is not displayed because parse doesn’t throw an exception if the JSON string is valid.

Catching exceptions

The JSON validator above uses the try-catch construction to display an appropriate message.

The source code displays the function doValidate(), and try-catch construction. The line, try { represents the start of the try block. The line, var result equals JSON.parse(inputText); is the code tat might cause the exception. The line, OutputElement.innerText equals "Valid JSON"; represents the statement that is only performed if no exception is caused. The line, catch { represents the start of the catch block. The line, OutputElement.innerText equals "Invalid JSON"; represents the code that is obeyed if the exception is caused.

The doValidate function is called when the Parse button is pressed in the JSON validator web page. If the user types in valid JSON, the JSON.parse method doesn’t throw an exception, and none of the statements in the catch block are performed. Instead, execution goes straight to the end of the method. However, if the JSON.parse method can’t parse the string that was typed in, the exception is generated and execution transfers immediately to the block of code under the catch keyword.

The try block can contain many statements. However, this might make it hard for you to work out which statement caused the exception.

CODE ANALYSIS

Exception handling

You might have some questions about how exceptions are handled.

Question: How does the exception stop the display of the Valid JSON message?

Click here to view code image

var result = JSON.parse(inputText);
outputElement.innerText = "Valid JSON";

Answer: The statements in doValidate that parse the input JSON and display the message are shown above. When the parse method throws an exception, the normal execution of this sequence of code is interrupted and program execution moves to the catch part of the try-catch construction. Valid JSON is not displayed because when parse throws an exception, execution does not get that far.

If no exception is thrown, the code in the try block is completed and execution then skips the statements in the catch block.

Question: How can a program get hold of the exception object?

A screenshot is displayed with the title that reads "JSON Validator." The application allows the user to enter the string input and check if it contain valid JSON. The text "Kaboom" is entered in the input field. When the parse button is clicked, it displays the output as : "Invalid JSON." The syntax error message that reads "unexpected token k in JSON at position 0".

Answer: The first version of the JSON Validator program ignored the error object produced by the JSON.parse function. However, we can add the display of the error message by picking up the error object as a parameter to the catch construction:

The screenshot displays the code in the catch part of the try-catch construction. The line, catch (error) { represents the catch with error parameter. The line errorElement.innerText equals error; is represented to display the error.

This is the code that runs in the catch part of the try-catch construction. It displays the error value (which is highlighted) on an element in the HTML to give the display above. You can find this version of the validator application in the example files in the Ch10 Advanced JavaScript\Ch10-02 JSON Validator Error folder.

Question: Can I throw my own exceptions?

Answer: Yes, you can. The throw statement is followed by the value that is being thrown to describe the error.

Click here to view code image

throw "something bad happened";

Question: What happens when an exception is thrown?

Answer: Throwing an exception stops the sequence of execution. Any statements following the throw statement are not performed.

Click here to view code image

throw "something bad happened";
console.log("This message is never printed");

In the code sample above, the second statement, which logs a message on the console, is never performed because when the throw is performed, the execution of this sequence of instructions is ended.

Question: Is it possible to return to a sequence of execution after an exception has been thrown?

Answer: No. Throwing an exception ends the running of a sequence of statements.

Question: Is it possible for the JSON stringify method to throw an exception?

Answer: Yes. It turns out that there are some JavaScript objects that can’t be saved into a string of text. Let’s see if we can make one. Go back to the Developer Console in the browser and start by making an empty object called infiniteLoop. Type the statement below and press Enter.

> var infiniteLoop = {}

Creating variables always returns an undefined result, so you should see the undefined message.

> var infiniteLoop = {}
<- undefined

Now we are going to add a property to the object that contains a reference that refers to the object itself. Type in the following statement and press Enter.

Click here to view code image

> infiniteLoop.loopRef = infiniteLoop

When you press Enter, the JavaScript console adds a new property to the infiniteLoop variable that contains a reference to the infiniteLoop variable. In other words, this variable now contains a reference to itself.

Click here to view code image

> infiniteLoop.loopRef = infiniteLoop
<- {loopRef: {…}}

Now, let’s try and stringify the value in infiniteLoop. Type the following and press Enter:

Click here to view code image

> JSON.stringify(infiniteLoop)

When you press Enter the stringify method tries to save the contents of infiniteLoop. It does this by working through each of the properties inside the value and saving each one in turn. It finds the loopRef property, so it follows that reference to save that value. The reference leads to the infinfiteLoop variable, so with stringify, this save process would go on forever, rather like a reflection between two parallel mirrors. Fortunately, the people who created the stringify method are aware of the problem and have added a test for what is called a “circular” reference. If you try to stringify an object that contains a reference to itself, you will get an error.

Click here to view code image

> JSON.stringify(infiniteLoop)
Uncaught TypeError: Converting circular structure to JSON
    --> starting at object with constructor 'Object'
    --- property 'loopRef' closes the circle
    at JSON.stringify (<anonymous>)
    at <anonymous>:1:6

Exceptions and errors

Now that we know how to throw and catch exceptions, we can consider how we can use them in our applications. However, before we do that, I want to talk about the two types of fault that can occur in a program:

Things that shouldn’t happen

Things that really shouldn’t happen.

Things that shouldn’t happen include users typing in numbers that are out of range (perhaps an age value of -99) and network connections failing. These are bad things that we expect. Things that really shouldn’t happen include faults in functions and methods that are used by our applications.

The starting point for the discussion of exceptions was the way that the JSON.parse method throws an exception if it is used to parse a string that does not contain valid JSON (for example, “kaboom”). This should never happen in the Tiny Contacts program. The only way that this could happen is if the browser storage is corrupted in some way. Is this really a problem? I would say yes, and I’ve added code to my Tiny Contacts application to deal with this.

The source code in the screenshot displays the modified version of the loadDataStore Function. The line, const STORE_INVALID equals 2; represents that the constant values are assigned for the status codes. The line, return STORE_EMPTY; returns a status code. The line, return STORE_INVALID; returns a status code. The line, return STORE_LOAD_OK; return a success code.

The code above is a modified version of the loadDataStore function from the Tiny Contacts application in the example programs in the folder Ch10 Advanced JavaScript\Ch10-03 Tiny Contacts Secure. The call of the JSON.parse method is now enclosed in a try block, and the catch block creates an empty contact store if the parse method fails with an exception. The first version of loadDataStore returned the Boolean value true if it worked and false if it failed. There are three possible ways that this version of loadDataStore can complete:

The data is not present in local storage because this is the first time the application has been used.

The data loaded from local storage is not valid JSON. (This will cause an exception in parse.)

The data was found and loaded successfully.

The function returns one of three status values to indicate which of these possible outcomes happened when loadDataStore was called. Programmers can then test this value to determine what happened when the contacts store was loaded.

These values have been declared using the keyword const. This means that their value cannot be changed by the program when it runs. This is sensible because they are being used to indicate status values. The return values from loadDataStore are used by the function doStartTinyData. If the store is empty or invalid, an alert is displayed for the user.

A screenshot displays the program with doStartTinyData function. The line, var loadResult equals loadDataStore(); tries to load the contact store. The line, case STORE_LOAD_OK; indicates that if the store loaded OK we don't do anything. The line, case STORE_EMPTY; indicates that if the store was empty we make a new one. The line, case STORE_INVALID: indicates that the store was corrupted, we make a new one.

It is very important that once we have created some error-handling code, we also create a way of testing it. In this case, I created a new application that breaks the storage. You can see it in Figure 10-1 and find the application itself in the folder Ch10 Advanced JavaScript\Ch10-04 Store Breaker in the examples. You can use this application to “break” the data storage for the Tiny Contacts application.

Figure 10-1 Store breaker

Click here to view code image

<!DOCTYPE html>
<html lang="en">

<head>
  <title>Store Breaker</title>
  <link rel="stylesheet" href="styles.css">
  <script src="breakstore.js"></script>
</head>

  <p class="menuHeading"> Store breaker</p>

  <p>
    <button class="menuButton" onclick="doBreakStore()">Corrupt the data store</button>
  </p>
  <p>
    <button class="menuButton" onclick="doEmptyStore()">Remove the data store</button>
  </p>
</body>
</html>

This is the HTML for the store breaker application. It contains two buttons. One button is pressed to corrupt the data store. It stores the string kaboom in the data store, which will cause JSON.parse to fail. The second button is pressed to remove the data store completely. These allow us to test the two possible errors.

The screenshot shows the source code for the store breaker application. The line, const StoreName equals "TinyContactsStore"; indicates that the name of the store is in local storage. The line, function doBreakStore() { represents the function which is called to break the JSON storage. The line, var reply equals confirm ("click ok to corrupt the data store"); is displayed to show a confirm dialogue. The line, if (reply) { checks if the user confirms perform the action; The line, local storage.setItem(storeName, "Kaboom"); saves an invalid store name. The line, function doEmptyStore() is called to empty local storage. The line, TotalStorage.removeItem(storename); removes the local storage item.

These functions use a feature of JavaScript that we haven’t seen before. The confirm function allows a user to confirm an action. It pops up a message box containing the prompt string and offers the user a chance to either confirm the action or cancel. If the user confirms the action by clicking the OK button, as shown in Figure 10-2, the confirm function returns the value true.

Figure 10-2 The confirm function display

A screenshot displays the store breaker application. It consists of two buttons 'corrupt the data store' and 'remove the data store.' A pop-up box is displayed with a message that reads, "This page says. Click the ok button to corrupt the data store." The 'ok' and 'cancel' buttons are also displayed in the popup dox.

PROGRAMMER’S POINT

Error management is crucial

Dealing with errors is time consuming and difficult. It can be hard to test an error handler. We had to write a special “breaking” program to test the error handling in the Tiny Contacts application. However, error management is a crucial part of software. Viruses and malware often attack systems by causing errors and then exploiting badly written or non-existent error handlers. When you are deciding how long it will take to create an application, make sure that you include the time it will take you to decide how errors are to be handled and write and test the components to deal with them.

Class design

From what we’ve learned up to now, we can regard a Java object as a container. We’ve seen that a program can add properties to an object so that it can assemble related items. We explored this by creating an object-based application that stores contact details. Object properties were added by the program one at a time, building up a complete set of contact information by adding name, address, and phone number properties to an “empty” object. This works well for small applications, but sometimes you want to map out your class design, rather than building it up as the program runs. And, as we shall see, using classes to design objects also brings benefits by reducing the amount of code that we write.

Fashion Shop application

Your lawyer client is very happy with her Time Tracker application. She’s been showing it to her friends, and they’ve been very impressed—particularly a friend who runs a fashion shop and has been looking for an application to help her manage her stock. She sells a range of clothing items and needs help tracking inventory. She’s keen to get your help, and she’s offering discounted prices or even free clothing in exchange. Free fashion sounds like an interesting idea, so you sit down with your new client and talk about what she needs.

She tells you that stock arrives from suppliers, and she enters the details in her stock book. For each different item that she sells, she stores a page of data in the book. She updates the stock level in the book when stock arrives from her suppliers and when she sells something. She shows you two of the pages from her book.

Figure 10-3 shows us what Imogen does when she works with the stock data. We can use this as the basis of our program specification. As usual, we draw some designs showing how the program will be used. There will be more than one design because this program will be spread across several “pages.” For each page, we will need to also write a story that describes how the page will be used. This will also allow us to work through the feature provided by that page to make sure that we know exactly what the program should do. “User stories” are an important part of software design. You can find out more about them at https://www.mountaingoatsoftware.com/agile/user-stories.

Figure 10-3 Fashion shop stock items

The screenshot presents the dress and pant stocks of Imogen's fashion. The details includes stock reference, stock level, price, description, color, pattern, and size.

Figure 10-4 shows the main menu of the program. Imogen can click the buttons to select pages to add dresses, pants, skirts, and tops to her stock. She can select an update page to edit any existing stock items to change their description or stock levels. She can also obtain a list of all her stock items by pressing the List button.

Figure 10-4 Fashion shop main menu

Figure 10-5 shows what Imogen would see when she presses the Dress button on the main menu to add a dress to stock. When she clicks Save on this page, the program will assign a stock number to the item and save it.

Figure 10-5 Fashion shop add item

When a new item is added to the store, the program displays an alert, as shown in Figure 10-6. This gives the stock number, which was assigned to the new item.

Figure 10-6 Add complete

The Update stock item button on the main menu starts a search for a given stock number that is to be updated. Figure 10-7 shows the search page. When the Find button is clicked, the program will search for a stock item with the given id value and display the item for editing.

Figure 10-7 Update Stock

The final button on the main menu shown in Figure 10-4 is the List button. Imogen will press this to generate a list of stock items that she can look through. Each item has an Update button that she can click (see Figure 10-8) to open the update page for that item.

Figure 10-8 Stock List

Imogen thinks this will be a good start for the application; you agree a price in stylish clothing and start working on the program. The first thing that you need to do is decide how the different stock items are going to be stored.

MAKE SOMETHING HAPPEN

Manage Imogen’s Fashions

The application in the sample folder Ch10 Advanced JavaScript\Ch10-05 Fashion Shop implements a working fashion shop store. It creates a set of test data that you can view. You can also create your own fashion items, store them, and then search for them by their stock reference. You should spend some time adding and editing stock items to get a feel for how it is used. Then we can start working out how each part works.

Store stock data

We could store information for a particular stock item in a JavaScript object by creating an empty object and then adding properties to it:

The screenshot displays the source code to store stock data. The line, myDress() is represented to create an empty object. The line, myDress.StockRef equals 221; adds a stockRef property.

The statements above create an object called myDress that contains all the data for the dress in Figure 10-3. However, there is a much easier way of creating objects that contain properties. We can create a class that tells JavaScript how to make a Dress object and what the object contains:

Click here to view code image

class Dress{
    constructor(stockRef, stockLevel, price, description, color, pattern, size){
        this.stockRef = stockRef;
        this.stockLevel = stockLevel;
        this.price = price;
        this.description = description;
        this.color = color;
        this.pattern = pattern;
        this.size = size;
    }
}

The JavaScript above doesn’t store any data. Instead, it tells JavaScript the properties that are stored inside a Dress object and how to construct one. The constructor method is called to create an instance of the Dress class. Now we can create a new Dress much more easily:

Click here to view code image

myDress=new Dress(221,8,60,"Strapless evening dress","red","swirly",10);

The new keyword tells JavaScript to find the specified class and run the constructor method in that class to create a new instance of the class. When the constructor method runs, it copies the parameter values into properties in the newly created object. The keyword this, which you can see in the constructor method above, means “a reference to the object that this method is running inside.”

The statement, this.price equals price is displayed in the screenshot. Here, the price next to 'this' represents the property of object, and the price to the right of the equals symbol represents the parameter to the function.

The confusing-looking statement above takes the price value that was supplied as an argument to the constructor and assigns it into a newly created price property on the object that is being created.

Click here to view code image

yourDress=new Dress(221,2,50,"Elegant party dress","blue","plain",12);
herDress=new Dress(222,5,65,"Floaty summer dress","green","floral",10);

If the word this is confusing, consider the two statements above. They create two Dress instances. Each time the constructor in the Dress class runs, it must set up a different object. In the first call of the constructor to set up the yourDress the keyword, this represents a reference to the yourDress object. In the second call of the constructor to set up herDress, the keyword this represents “a reference to the herDress object.”

CODE ANALYSIS

Objects and constructors

Question: What happens if I create a class that doesn’t contain a constructor?

Answer: If you don’t add a constructor method, JavaScript will create one for you that is empty.

Question: What happens if I omit some arguments from the call of a constructor?

Answer: If you omit the arguments to a call of a JavaScript function or method, the values of those parameters are set to undefined.

Click here to view code image

shortDress = new Dress(221,0,50);

This statement would create a Dress with the stock reference (221), stock level (0), and price (50), but the description, color, pattern, and size properties would be set to the value undefined.

Question: What is the difference between a function and a method?

Answer: A method is exactly like a function, but it is declared within a class. The constructor for a class is the first method that we have created. Later in this section, we will discover how we can add methods to classes to make objects that can provide services for our programs. A function is declared outside of any class.

Question: I still don’t understand this. What does it mean?

Answer: To understand what this does, it is a good idea to remember the problem it is solving. When a constructor method runs it must write property values in the object that it is setting up. The constructor for the Dress object needs to set the values of stock reference, stock level, price, and so on. JavaScript provides the keyword this to represent that reference.

Object-oriented design

It would make sense to create a class to hold each kind of data we wish to store. Programmers call this object-oriented programming. The idea is that elements in a solution are represented by software “objects.” The first step in creating an application is to identify these objects.

In the English language, words that identify things are called nouns. When trying to work out what classes a system should contain, it’s a good idea to look through the description of a system and find all the nouns. As an example, consider the following description of a fast-food delivery application.

“The customer will select a dish from the menu and add it to his order.”

I’ve identified four nouns in this description, each of which will map to a specific class in the application. If I were working for the fast-food delivery company, I would next ask them what data they stored about customers, dishes, menus, and orders.

PROGRAMMER’S POINT

Don’t write any code before you have completed your data design

For a commercial project, you would spend a lot of time on the design of the classes in your system before you wrote a single line of code. This is because design mistakes are much easier to fix at the beginning of the project, rather than after code has been written.

In the case of our fast-food management example above, we would want to make sure that the customer class holds all the information required to make the business work. We would do this by creating “paper” versions of the classes and then working through all the usage scenarios (creating an order, cooking an order, and delivering an order) to make sure that all the data the application needs is being captured.

If the application must store a customer telephone number so that the delivery driver can call for directions if needed, it is best to discover this at the beginning of the project, rather than after the entire user interface has been created.

We will write code and discuss it as we go along because we are learning about data design and JavaScript programming. However, if I were creating a professional solution, I’d spend a lot of time away from JavaScript working out the design before I created any classes.

When we talk to our fashion shop customer, she’ll talk about the dresses, pants, hats, tops, and other items that she wants the application to manage. Each of these could be objects in the application and can be represented by a class. Each class will contain the properties that describe that item of clothing. Let’s start by considering just the information for dresses and pants and create some classes for these objects. We already have a class for Dress, so let’s make one for Pants.

Click here to view code image

class Pants{
    constructor(stockRef, stockLevel, price,
                description, color, pattern, length, waist){
        this.stockRef = stockRef;
        this.stockLevel = stockLevel;
        this.price=price;
        this.description=description;
        this.color = color;
        this.pattern = pattern;
        this.length = length;
        this.waist = waist;
    }
}

The code above defines a Pants class. It contains a constructor method to set up the contents of that class. Our program can now create instances of these classes:

Click here to view code image

myDress=new Dress(221,8,60,"Strapless evening dress","red","swirly",10);
myPants=new Pants(222,1,45,"Good for the workplace","black","plain",30,30);

When I wrote this sample code, I found myself using a lot of block-copy commands in the editor when I created the constructor. This is not necessarily a good thing.

PROGRAMMER’S POINT

Try to avoid repeating code

The Dress and Pants classes have quite a few elements in common. They both contain stockRef, stockLevel, and price attributes. You might think that would be a good idea to have two copies of the code that deals with these attributes, one in the Dress class and the other in the Pants class. However, this is not a good idea. I try to avoid having repeated copies of code in a project because if I find a bug in one copy, I then have to find all the other places I’ve used that code and fix those as well.

A good programmer will try to write a piece of code exactly once. If the code is used more than once in an application, a good programmer will convert the code into a method or function and then call the method each time it’s needed.

This is not about making sure that our programs are as small as we can make them. It’s about self-preservation. If you block copy a piece of code into lots of different places in your application, you’ll have a real problem if you find a bug in the copied code. You’ll need to go through your entire application and fix all the broken copies of that code. On the other hand, if you find a bug in a method, you can fix it just once, and it is fixed for every situation in which that method is used. Fortunately, there is a way we can remove the need for numerous copies of the same code, which we will discuss now.

If I find myself copying program text from one place to another, I take this as a trigger to step back from the problem and think about different ways of structuring my solution.

Creating superclasses and subclasses

JavaScript classes support a mechanism called inheritance. This is another aspect of object-oriented design. Inheritance lets us base one class on an existing superclass. This is called extending the superclass. We can greatly simplify the design of our classes for the Fashion Shop program by creating a superclass, which we can call StockItem.

The StockItem class will store all the attributes common to all the data items in the shop. These are the stock reference, price, color, and stock level. The Dress and Pants classes will extend the StockItem class and add the properties particular to dresses and pants. Figure 10-9 shows the arrangement of the classes we’re creating. In software design terms, this is called a class diagram.

The class diagram shows the relationship between classes in a system. Figure 10-9 shows that both Pants and Dress are subclasses of the StockItem class (meaning they are based on that class). We could also say that the StockItem class is the superclass of Dress and Pants.

Figure 10-9 Fashion shop class diagram

The class diagram shows the relationship between the classes. Here, the superclass 'StockItem' consists of stockRef, stockLevel, price, description, color, and pattern. The first subclass 'Dress' shows the size, and the second subclass 'pants' contains length, and waist. The subclass 'dress' and 'pants' inherits data from the parentclass 'StockItem.'

In real life, inheritance means stuff that you get from people who are older than you. In JavaScript terms, inheritance means the attributes a subclass gets from its superclass. Some programmers call the superclass the parent class and the subclass the child class.

The key to understanding inheritance is to focus on the problem it is solving. We’re working with a collection of related data items. The related items have some properties in common. We want to implement the shared properties in a superclass and then use this superclass as the basis of subclasses that will hold data specific to their item type. That way, we only need to implement the common properties once, and any faults in the implementation of those properties need only be fixed once.

Working in this way has another advantage. If the fashion shop owner decides that she would find it useful to be able to store the manufacturer of the items she’s selling, we can add a manufacturer attribute to the StockItem class, and all the subclasses will inherit that attribute, too. This will be easier than adding the attribute to each class.

Abstraction using objects

Another way to think of this is to consider what we are doing as abstraction. We first encountered abstraction in Chapter 9 in the section “Use a data schema,” where we created a design for all data stores rather than building individual ones. We have seen abstraction means “stepping back” from the problem and taking a more general view. In our conversations with the fashion shop owner, we would like to talk in general terms about the things she would like to do with the stock in her shop. She will want to add stock items, sell stock items, find out what stock items she has, and so on. We can talk to her about her stock in abstract terms and then later go back to fill in the specific details about each type of stock and give them appropriate behaviors.

Programmers use abstraction a lot. They talk about things like stock items, customers, and orders without considering specific details. Later, they can go back and “fill in the details” and decide what particular kinds of stock items, customers, and orders with which the application will work. We’ll create different kinds of stock items in our Fashion Shop program. The StockItem class will contain the fundamental properties for all the stock, and the subclasses will represent more specific items.

The diagram in Figure 10-9 is called a class hierarchy. It shows the superclass at the top and subclasses below. When you travel down a class hierarchy, you should find that you move from the abstract toward the more concrete. The least abstract classes are Pants and Dress because these represent actual physical objects in our application.

CODE ANALYSIS

Understanding inheritance

Here are some questions about object-oriented design and inheritance. Try to come up with your own answers before reading the answers I’ve provided.

Question: Why is the superclass called “super”?

Answer: This is a good question and one that has confused me for a long time. The word “super” usually implies something better or more powerful. A “superhero” has special powers that ordinary people do not. However, in the case of a superclass, this doesn’t seem to be the case. The superclass has fewer powers (fewer properties) than the subclass that extends it.

I think the word “super” makes sense if you consider it as something that classes descend from. The super object is above the sub object, just like superscript text is above subscript text. The object is the superclass because it is above everything else.

Question: Which is most abstract, a superclass or a subclass?

Answer: If you can work out the answer to this question, you can start to consider yourself an “object-oriented ninja.” Remember that we use abstraction as a way of “stepping back” from the elements in a system. We’ll say “receipt” rather than “cash receipt” or “StockItem” rather than “Pants.”

Question: Can you extend a subclass?

Answer: Yes, you can extend a subclass. We could create a Jeans class that extended the Pants class and contained a style property that could be “skinny,” “high waist,” “bootcut,” or “flared.” In JavaScript, there is no limit to how many times you can extend classes, although I try to keep my class diagrams fairly shallow, with no more than two or three subclasses.

Question: Why is the pattern property not in the StockItem class?

Answer: Most impressive. Well spotted. The pattern property is in both the Dress and Pants classes. It might seem sensible to move the property into the StockItem class with the color, stockLevel, and price attributes.

The reason I haven’t done this is that I think that the fashion shop might sell some stock items that have no pattern—for example, items of jewelry. I want to avoid a class having data properties that aren’t relevant to that item type, so I’ve put pattern values into the Dress and the Pants class instead.

I’m not particularly happy with this because ideally, a property should appear only in one class, but in real-world design, you come across these issues quite often. One possible way to resolve the issue would be to create a subclass called PatternedStock that is the superclass for Dress and Pants. However, I think that would be too confusing.

Question: Will our system ever create a StockItem object?

Answer: JavaScript will allow the creation of a StockItem object (an instance of the StockItem class), but it’s unlikely that we would ever actually create a StockItem on its own.

Some programming languages, such as C++, Java, and C#, allow you to specify that a class definition is abstract, which stops a program from making instances of that class. In these languages, an abstract class exists solely as the superclass for subclasses. However, JavaScript does not provide this feature.

Question: The owner of the fashion shop thinks that one day she might like to keep track of which customer has bought which item of stock. This will allow her to look at their past purchases and make recommendations for future purchases. Here are three ways to do this. Which would make the most sense?

Extend the StockItem class to make a Customer subclass that contains the customer details because customers buy stock.

Add customer details to each StockItem.

Create a new Customer class that contains a list of the StockItems that the customer has bought.

Answer: Option 1 is a bad idea because a class hierarchy should hold items that are in the same “family.” In other words, they should all be different versions of the same fundamental type. We can see that there is some association between a Customer and a StockItem, but making a Customer a subclass of StockItem is a bad idea because they’re different kinds of objects. The StockItem holds attributes such as price and stockLevel, which are meaningless when applied to a Customer.

Option 2 is a bad idea because several customers might buy the same StockItem. The customer details cannot be stored inside the StockItem.

Option 3, adding a new Customer class, is the best way to do this. Remember that because objects in JavaScript are managed by references, the list of items in the Customer class (the items the customer has bought) will just be a list of references, not copies of StockItem information.

Store data in a class hierarchy

Now that we’ve decided using inheritance is a good idea, we need to consider how to make it work with our classes.

Click here to view code image

class StockItem{
    constructor(stockRef, stockLevel, price, description, color){
        this.stockRef = stockRef;
        this.price=price;
        this.description=description;
        this.stockLevel = stockLevel;
        this.color = color;
    }
}

This is the StockItem class file. It contains a constructor method to set up a StockItem instance. The StockItem class will be the superclass of all the objects that the fashion shop will be selling. We can create a Dress class that is a subclass of the StockItem class to hold information about dresses that the fashion shop will be selling.

Click here to view code image

class BrokenDress extends StockItem{
    constructor(stockRef, stockLevel, price, description, color, pattern, size){
        this.pattern = pattern;
        this.size = size;
    }
}

The BrokenDress class extends the StockItem class. It only contains the properties that are specific dresses. However, we have a problem if we try to use the BrokenDress class:

Click here to view code image

myDress=new BrokenDress(221,8,60,"Strapless evening dress","red","swirly",10);

The statement above tries to create an instance of the BrokenDress class. This statement will fail with an error:

Uncaught ReferenceError: Must call super constructor in derived class before accessing ‘this’ or returning from derived constructor at new BrokenDress

JavaScript is telling us that to create a BrokenDress, our constructor must first create a StockItem. The constructor in the BrokenDress class that we have created doesn’t do this, so this class is broken (hence the name). To fix it, we need to make a Dress class that contains a constructor that first constructs the super object. JavaScript provides the super keyword, which can be used in a constructor to call the constructor in the superclass. The constructor method for the Dress class calls the constructor method in the StockItem class by means of the super keyword.

A screenshot shows the JavaScript code using constructor. The line, super (stockRef, stockLevel, price, color); is represented to call the constructor in the superclass.

MAKE SOMETHING HAPPEN

Investigate using super to create instances

The example application in the folder Ch10 Advanced JavaScript\Ch10-06 Fashion Shop Classes contains the StockItem, BrokenDress, and Dress classes that you can experiment with. You can use the Developer View to debug the process of creating a Dress by placing a breakpoint at the first statement of the Dress constructor and then stepping through the JavaScript as the super keyword is used to call the constructor in the StockItem.

Add a method to give an object a behavior

Things that are part of a class are called the members of the class. We know how to create properties which are members of a class. Now we are going to find out how to add method members. Adding a method member to a class allows it to do things for our program. At the moment, the classes we have created don’t contain any methods. A useful method might be one that allows a Dress to provide us with a string describing its contents. We can use this to produce the text to be displayed for the Stock List menu item.

A screenshot displays the JavaScript code with getDescription() in the dress class. The line getDesctription() represents the getDescription method. The line, size: plus this.size; is displayed to assemble a string containing a description. The line, return result; returns the string.

The Dress class above contains a method called getDescription that can be called to get a description of the contents of the object. Note that the method uses the this reference to access the properties of the object that is being described. A program can use this method to get a string that describes a particular dress.

Click here to view code image

myDress=new Dress(221,8,60,"Strapless evening dress","red","swirly",10);
console.log(myDress.getDescription());

The first statement above creates a dress object called myDress. The second statement uses the getDescription method on the myDress object to display a description of the dress. It would display the following:

Click here to view code image

Ref:221 Price:60 Stock:8 Description:Strapless evening dress Color:red Pattern:swirly Size:10

The Fashion Shop application will use the getDescription method to build an HTML element to be displayed in a stock list.

MAKE SOMETHING HAPPEN

Investigate the getDescription method

The example application in the Ch10 Advanced JavaScript \Ch10-07 Fashion Shop Methods folder contains the StockItem, Dress, and Pants classes that you can experiment with. You can use the Developer View to create Dress and Pants instances and call the getDescription method to view their contents.

Objects and polymorphism

The next thing I want to talk about has the most impressive name in the entire book. The word polymorphism comes from the Greek language and means “the condition of occurring in multiple forms.” In software engineering, it means regarding an object in terms of what it can do rather than what it is.

A great thing about the getDescription method is that other parts of the Fashion Shop application don’t need to know how the Dress and Pants classes store their data or even what data is stored inside them. A part of the program that needs to produce a description of a Dress doesn’t have to pull out the various properties from a Dress instance; it just has to call the getDescription method to get a string that describes that particular dress. What’s more, this part of the program doesn’t need to care whether it is dealing with dresses or pants, it can just view these items as “things I can use getDescription to get a description of.”

Polymorphism means thinking about objects in terms of what they can do, rather than what they are, and allowing each object to perform a particular action in a way specific to that object. A given object can be viewed in many ways, depending on what you want to do with it. Different parts of the Fashion Shop will view objects in terms of abilities such as “get a description string,” “set a discount,” “save,” and “load.” Each of these abilities can be provided by methods inside the object with a characteristic name, which can then be used by the rest of the system to perform that action. Part of an object-based design process involves identifying the behaviors required of objects and specifying them as methods.

Overriding methods in subclasses

A fundamental principle of object-oriented design is that a given object contains all the behaviors for that particular object. In this respect the getDescription method in the Dress class is not good. The first four items that are used to build the description string are not held in the Dress class. Instead, they are held in the StockItem superclass.

A screenshot displays the JavaScript code with getDescription(). The line, var result equals "Ref:" plus this.stockRef plus represents the value from the StockItemClass. The line, price: plus this.Price plus represents the value from the StockItem Class. The line, stock: plus this.stock plus represents the value from the StockItem Class. The line, Description: plus this.description plus represents the value from the StockItem Class. The line, color: plus this.color plus represents the value from the StockItem Class. The line, pattern: plus this.Pattern plus represents the value from the StockItem Class. The line, size: plus this.size plus represents the value from the StockItem Class.

If we added a new property to the StockItem class, we would have to also change the getDescription method in the Dress class to display the new property. If StockItem had many subclasses, we would have to change every one. What we would like to do is make the StockItem class responsible for delivering the description of what it contains, and then use that description in the Dress class. It turns out that we can do this by creating a getDescription method in the StockItem class and then overriding the getDescription method in subclasses of StockItem.

A screenshot presents the JavaScript code to create getDescrition method in a class and then to overrides in a subclass. The line, class Dress extends StockItem, overrides the getDescription method in the super class. The line, var result equals super.getDescription() plus, is represented to call the getDescription from the superclass.

Both StockItem and Dress contain a getDescription method. We say that the getDescription method in the Dress class overrides the getDescription method in the StockItem class. A description of a Dress must include a description of the contents of the super object of Dress, so the JavaScript super keyword is used to invoke the getDescription method in the StockItem object. Within a method in a class the word super is a reference to the super object (the one above the object in the class hierarchy).

CODE ANALYSIS

Understanding super

The example application in the folder Ch10 Advanced JavaScript \Ch10-08 Dress Shop Override Methods contains the StockItem, Dress, and Pants classes that work in exactly the same way as the previous example. But these versions use overridden versions of the getDescription method. You can use the debugger to explore how the overridden method is called. However, you might also have some questions.

Question: How does the super reference work?

Answer: When a program is running JavaScript keeps a lump of data about each class that is being used. One of the items of information that JavaScript stores is the superclass of each class. When JavaScript sees the keyword super in a statement it looks in the definition of the class the method is part of to find the superclass. It then finds the specified method in the superclass and runs it.

Question: What would happen if you tried to use super in a class at the top of a hierarchy?

Answer: This would cause an error because JavaScript would not find a super method.

Question: Can you override a function in a JavaScript program?

Answer: No. A function is not part of an object. You can only override a method, which is part of an object.

Static class members

You will have noticed that the demonstration Fashion Shop app contains a lot of test data. This is generated by the data objects themselves. The data and methods to create test dresses are not part of any Dress instance. Instead, they are part of the Dress class itself. JavaScript lets us do this by creating properties and methods, which are static. The word “static” in this context means “always there,” rather than unchanging. We don’t need to use new to create an instance of the Dress class to get hold of the static members of the class. These members exist as soon as the JavaScript class is loaded by the browser.

The screenshot presents a program by using getTestItems method. The line, static colors equals ["red", "blue", "green", "yellow"]; represents static ray of colors. The line, static patterns equals ['plain', 'striped', 'spotted', 'swirly']; represents Static array of patterns. The line, static sizes equals [8, 10, 12, 14]; static array of sizes. The line, static getTestItems(dest) { represents the Static function to get test data. The line, var stockNo equals StockItem.getLargestStockRef(dest) plus 1; ensures we don't repeat stock numbers. for (let color of Dress.colors) { Work through the colors. The line, for (let pattern of Dress.patterns) { work through the patterns. The line, for (let size of Dress.sizes) { work through the sizes. The line, let price equals StockItem.getRandomInt(10, 200); is represented to get a random price. The line, let stock equals StockItem.getRandomInt(0, 15); is represented to get a random stock level. The line, let description equals color plus " " plus pattern plus " dress"; represented to build a description string. The line, new Dress(stockNo, stock, price, description, color, pattern, size); creates a new dress and stores it. The line, stockNo equals stockNo plus 1 is represented to advance the stock number.

The method getTestItems above works through arrays of colors, patterns, and sizes to create a large number of dress stock items, which it adds to an array supplied as a parameter. The getTestItems method is static, so it can be called without the program needing to make an instance of the Dress class. The data arrays that are used by the getTestItems method are also defined as static. The getTestItems method also uses the static method getRandomInt, which is declared in the StockItem class. The getRandomInt method is used to obtain random prices and stock levels for the dresses that are created. It is based on the function that we created to make a random dice. The getLargestStockRef method is used to search the fashion store to find the highest stock number in it. This ensures that the function doesn’t create any stock items with the same stock number as existing ones.

The static members of a class are marked with the static keyword. Static class members are accessed via the class identifier so the above method can be used as follows to create an array full of Dress values:

demo = []
Dress.getTestItems(demo);

CODE ANALYSIS

Understanding static

The example application in the folder Ch10 Advanced JavaScript \Ch10-09 Fashion Shop Static Members contains Dress and Pants classes that contain static getTestItems method that create large amounts of data that can be used to test our system. However, you might also have some questions.

Question: Does static mean that a class member cannot be changed?

Answer: No. The static keyword affects where a class member is stored, not what you can do with it. Static marks members of a class that are part of a class, not an instance of the class. If you want to make a variable that cannot be changed you can declare it as const.

Question: Can you give me an example of a good use for static members of a class?

Answer: Static members are things that you want to store for the entire class. Suppose that you wanted to set a maximum price for all the dresses that the fashion shop sells. This could be used to help detect when someone mistypes a price value. This value should be stored in a static member of the class since it does not need to be stored with every dress. If we need to change the maximum price of a dress, we can just update the static value and the maximum price for all the dresses will be changed.

You make a method member of a class static when you want to use the method without creating an instance of the class. The JavaScript Math class contains lots of static methods to perform mathematical functions. These are declared as static so that we don’t have to create an instance of the Math class to be able to use them.

Question: Where does the stock ref number come from when we create a new stock item?

Answer: Each item of stock has a stock reference number. This number identifies a stock item in the same way that a given credit card number identifies a credit card. Imogen will enter the stock reference number to find an item she wants to edit. It is very important that each stock item has a unique stock reference number. The getLargestStockRef method searches through all the items and returns the largest stock reference that it has found. The program then adds 1 to this value to get the next stock number to be used.

A screenshot displays the usage of getLargestStockRef method in a program. The line, if (items.length equals equals 0), is constructed to check if there are no items and returns 0. The line, var largest equals items[0].stockRef; is represented to start with the first stock reference number.

A screenshot displays the use of for construction to find the largest number. The line, for (const item of items) searches for the stock items. The line, if (item.stockRef greater than largest) checks if the item has a larger stock reference and saves it. The line, return largest; returns the largest stock number.

Data storage

We have one last problem to solve before we can build the finished solution. We need a way of saving the dress shop data. The Tiny Contacts application that we created in Chapter 9 used JSON to encode the contact objects into text that was then stored as strings in browser local storage. We can do something similar, but the use of a class hierarchy makes it a little bit trickier. To understand why, consider what happens when we convert a dress value to a string using the JSON.stringify method.

Click here to view code image

{"stockRef":1,"stockLevel":"11","price":"85",
"description":"red plain dress","color":"red","pattern":"plain","size":"8"}

The text above is a JSON string that describes a dress. It contains all the properties in a Dress instance, including those in the StockItem object superclass. When we load this object back into our program we want to be able to use it as a Dress object. Unfortunately, there is nothing in the JSON string that tells a program reading it that this is a stored Dress value.

Add type information to JSON

The way to fix this is to add an extra property to our data that gives the type of the data. We can do this in the constructor for the class:

This is the modified Dress constructor. We can modify the constructor for the other types of clothing so that they create an appropriate type property. For example, the Pants constructor must set a type value of "pants" and so on.

Use the stored type property

Click here to view code image

{"stockRef":1,"stockLevel":"11","price":"85","type":"dress",
"description":"red plain dress","color":"red","pattern":"plain","size":"8"}

The JSON above describes a dress that contains a type property. I’ve highlighted the type information in yellow. What we need now is a way of creating a Dress instance from this JSON source string. I created a member function in the StockItem class to do this. The function is called JSONparse. It takes in a string of JSON and returns an object of the type specified by the type value in JSON. It uses a switch construction to decide what type of object to create.

"The screenshot explains the JSONparse method. The line, static JSONparse(text) { represents the Static method to read a stock object. The line, var rawObject equals JSON.parse(text); creates a raw object from the JSON string. The line, var result equals null; creates an empty result; The line, switch (rawObject.type) { decides which type of object is being loaded. The line, result equals new Dress(); makes and empty dress object. The line, result equals new Pants(); is represented to make an empty Pants object. The line, Object.assign(result, rawObject); copies the properties from the object into the result."

The JSONparse method also uses a method that we have not seen before. It is called Object.assign, and you can see it used in the last but one statement in the method. The Object.assign function copies all the data properties from one object to another. The program uses this to take all the data properties from the JSON object that we read and copy them into the empty object that we have just created. The first argument to the assign function is the destination object for the copy. This is the newly created object of the required type. The second argument to the assign function is the rawObject that was loaded from JSON. This contains all the data properties.

CODE ANALYSIS

Load and save

The example application in the Ch10 Advanced JavaScript \ Ch10-10 Fashion Shop No Test Data folder is a version of the Fashion Shop that doesn’t generate test data when first started. You can create and store stock items and they will be persisted when the browser is closed. It uses local storage in exactly the same way as the Tiny Contacts program, but it creates an array of JSON strings to store the data.

Question: The object that we loaded from the JSON object contains all the data properties that the program needs. Why do we have to copy it into another object?

Answer: This is because a Dress instance contains function members as well as data members. The system needs to be able to ask a Dress instance to do things like getDescription. An object created from JSON will not have these methods. So we need to create an “empty” Dress instance that contains the required methods and then add the data from the object that we have read from JSON.

Question: Why has the JSONparse method been made static?

Answer: The JSONparse method is called to read stock items from storage. It has to be static because when the program is first started there are no stock items loaded.

Question: Do you need a copy of the JSONparse method in every stock class (for example Dress and Pants)?

Answer: No. The nice thing about this is that a single copy of the JSONparse method in the StockItem class will load data for any of the classes because it just copies what has been saved. However, you do need to make sure that the switch statement in the JSONparse method is kept up to date. If you add a new type of stock (perhaps hats), you would have to add a case for that type to the switch.

Build a user interface

We now have all the behaviors that we need to make the Fashion Shop application. We can put all the different kinds of data in objects which can be saved and loaded. Our class-based design means that data properties shared by all the different objects are only stored in one place. The only thing missing is the user interface element. We need a menu system for the application along with views of the different types of data.

Make stock items display themselves

We have already built HTML documents that look very similar to parts of the Fashion Shop application. When we created the Tiny Contacts application, we created schema objects to describe the display elements that were needed. We can use the same approach to design HTML elements for each of the data classes in the Fashion Shop. If you’re not sure how we used schemas to design an HTML document, take a look in the “Use a data schema” section in Chapter 9.

Click here to view code image

static StockItemSchema = [
    { id: "price", prompt: "Price", type: "input" },
    { id: "stockLevel", prompt: "Stock Level", type: "input" },
    { id: "description", prompt: "Description", type: "textarea", rows: 5, cols: 40 },
    { id: "color", prompt: "Color", type: "input" }];

The code above shows the display schema for the StockItem class. This is the same schema design as we used for the Tiny Contacts application. There is an entry for each item to be displayed. The item gives the id of the property, the prompt to be displayed, and the type of the input. Three of the items are single-line inputs, and one is a text area. If you take a look at Figure 10-5 from earlier in this chapter, you will see how this schema defines the display of the top four values to be entered.

The buildElementsFromSchema method in JavaScript is displayed. The line, for (let item of dataSchema) works through the schema. let itemElement equals StockItem.makeElement(item); is represented to create a display element. The line, HTMLdisplay.appendChild(itemElement); is displayed to add the element to the page.

The buildElementsFromSchema method works through the elements in a schema and uses a function called makeElement to create each element from the schema information and add it to an HTML element. It is the same mechanism that was used to create the display of the Tiny Contacts application.

Click here to view code image

getHTML(containerElementId) {
    StockItem.buildElementsFromSchema(containerElementId, StockItem.StockItemSchema);
}

The StockItem class contains a method called getHTML that calls buildElementsFromSchema with the parameters required to build the part of a display needed to edit a StockItem. Now that we know how to build the display for a StockItem, we can consider how to build the display for a Dress.

The source code to build the display for the dress is displayed in the screenshot. The line, { id: "size", prompt: "Size", type: "input" }]; represents the schema for the dress display. The line, getHTML(containerElementId) represents the function to add the property elements to an HTML document. The line, super.getHTML(containerElementId); is represented to add the elements from the parent object. The line, StockItem.buildElementsFromSchema(containerElementId, Dress.DressSchema); add the elements from the dress.

The code above is the code that builds the display for the dress. The getHTML method uses a schema that defines just the extra elements that need to be added to the HTML document for the dress. It calls the getHTML function of its super object (which is the StockItem) to get the HTML for that object and then adds its own elements on the end.

CODE ANALYSIS

Creating HTML

A great programming language is one where you can create code that you are proud of. I’m quite proud of this HTML-generating code. It is easy to use and easy to extend. We can add more stock types and easily express what each stock type contains. However, you might have some questions about it.

Question: What does this code do again?

Answer: Good question. Remember that our data design has given us some classes that hold all the different data properties in a stock item. We have used inheritance to create a superclass called StockItem that holds all the properties shared by all the stock items (such as the price and the number of items in stock). Then we’ve created subclasses of StockItem that hold data specific to that type of item (such as the length and waist properties of Pants).

If we want the user to interact with these properties, we will need to create HTML (labels and input elements) in the HTML document displayed by the browser. We could do this by hand, but it would be tedious. When we made the Tiny Contacts application, we created a schema object that defined the properties to be displayed and then wrote a method that that worked through the schema making HTML elements to edit each item. Think of a schema as a “shopping list” of items to be displayed.

The process described above takes the same approach as we used for Tiny Contacts and adds a schema to each type of stock item. It uses the super keyword so that the display builder (the getHTML method) in Dress can call the getHTML method in the StockItem class. It is necessarily complicated, but if you stare at it hard enough, it does make sense. And if you understand it, you can call yourself a “class hierarchy ninja.”

Question: What would I need to do if I wanted to add a new data property to the StockItem class?

Answer: This is a situation in which this approach would pay off. If Imogen decides that she wants the system to record some new data in the StockItem class, we could add a new item to the StockItem schema. The display elements produced would be added to the edit displays of all the stock items because they are all subclasses of StockItem.

Start the application

This application uses four variables that are shared between all the functions:

Click here to view code image

var mainPage;   // HTML element that contains the user interface
var dataStore;  // Array of stock items
var storeName;  // name of save data in local storage
var activeItem; // currently active stock item (for entry and edit)

When the Fashion Shop starts, these variables must be set up. The body element of the HTML document containing the application contains an onload attribute that specifies the function to be called when the page is loaded. This function starts the Fashion Shop running. The function is called doStartFashionShop.

Click here to view code image

<body onload="doStartFashionShop('mainPage','fashionShop')" class="mainPage">

The function doStartFashionShop is very similar to the function doStartTinyContacts that we created in Chapter 9 to start the Tiny Contacts application. This function needs to load the stock data from the browser and set up the other shared variables.

A screenshot shows the use of doStartFashionShop function in JavaScript. The line, mainPage equals document.getElementById(mainPageId); Set mainPage to refer to the page container. The line, storeName equals storeNameToUse; sets the name of the local storage string. The line, loadDataStore(); is represented to load the stock data. The line, doShowMainMenu(); is displayed to show the main menu.

The last statement in doStartFashionShop displays the user menu. Lets take a look at how that works.

Create user menus

The user interacts with our program by pressing buttons on the screen that select the various menu options. If you look back to Figure 10-4, you can see the main menu for the display. Each of the program options is selected by pressing a button, and when the button is pressed, the application calls the function for that option.

Click here to view code image

function doShowMainMenu() {
    openPage("Main Menu");

    showMenu(
        [{ desc: "Add Dress", label: "Dress", func: "doAddDress()" },
        { desc: "Add Pants", label: "Pants", func: "doAddPants()" },
        { desc: "Add Skirt", label: "Skirt", func: "doAddSkirt()" },
        { desc: "Add Top", label: "Top", func: "doAddTop()" },
        { desc: "Update stock item", label: "Update", func: "doUpdateStock()" },
        { desc: "List stock items", label: "List", func: "doListFashionShop()" }]);
}

I’m using yet another schema to describe each menu option. The function showMenu works through the schema and builds the display. If you look back to Figure 10-4, you can map the application main menu onto the items in the schema above. The function openPage removes all the elements on the page and displays a heading.

Add a stock item

The menu calls an add function for each stock item. The doAddDress function looks like this:

function doAddDress() {
    addStock(Dress);
}

It calls the addStock function and does something we’ve not seen before. It uses the Dress class as an argument to the call of addStock. We do this so that we can have a single addStock function that can create any type of stock item.

The source code to add a stock item is displayed. The line, openPage("Add " plus activeItem.type); displays a new page. The line, activeItem.getHTML(mainPage); is displayed to get the new HTML for the new item. The line, { desc: "Cancel add", label: "Cancel", func: "doShowMainMenu()" }]); is displayed to show a menu for the add page.

The addStock function makes a new item of the required class (the class is supplied as a parameter). It then creates a new display page and fills it with the HTML generated by the new item. At the end of the page, the function builds a menu containing Save and Cancel buttons. The function handler for the Cancel button just displays the main menu. The function for the Save button copies the inputs from the HTML elements into a new copy of the stock item. This function has the name doSaveAdd. The job of doSaveAdd is to copy the data from the HTML document into the currently active item. This item is then stored in the data store.

A screenshot shows the source code to copy the data from the HTML document into the active item. The line, activeItem.loadFromHTML(); is represented to load the data from the HTML into the new item. The line, activeItem.stockRef equals StockItem.getLargestStockRef(dataStore) plus 1; is displayed to assign a stock number. The line, dataStore[dataStore.length] equals activeItem; stores the item. The line, saveDataStore(); saves the data store. The line, doShowMainMenu(); displays the main menu.

Exploring the Fashion Shop application

There is a lot to explore in the Fashion Shop and you can learn a lot by exploring it. The application is heavily based on the Time Tracker application. I would strongly advise you to spend some time going through the code. You can use the Developer View debugger to work through the code as it runs. The great thing about the application is that it is very clear what the intent of each function is. For example, the edit function, which we have not explored in this chapter, must find a stock item to be edited, make that item the active item, and when the edit is completed, copy the edited properties from the HTML document into the data store.

Note that we have not explored the function that provides a list of stock items. You can use it, and you can look at the code that makes it work, but we will be investigating that function and adding some great features to it in the next chapter.

MAKE SOMETHING HAPPEN

Expand the fashion shop

You can also learn a lot about programming by adding features to an existing application. Here are some things that you might like to do with the Fashion Shop application:

Add a new type of clothing called suit. A suit has the properties jacket size, pant size, color, pattern, and style. You can do this by adding a new class that is a subclass of StockItem.

Add a new property called manufacturer, which is to be stored for all the items in stock. You can do this by adding a new attribute to the StockItem class.

Add some data validation to the application. At the moment the user can save stock item records that have missing data fields. Write a function that tests for empty fields and only allows a record to be saved if all the fields have been filled in.

Create a totally new data storage application, which can store information for another business, perhaps a fishing tackle store. You should find this quite easy to do. You can use the Fashion Shop application as a great starting point.

What you have learned

In this chapter, you learned how JavaScript objects allow programs to store related items as properties of a single object and how to make programs that work with objects.

JavaScript programs can create and throw exception objects that describe an error that has been detected by the code. JavaScript statements that may throw exception objects can be enclosed in a try block as part of a try-catch construction. The catch element of the construction contains JavaScript code that only runs in the event of an exception being thrown. This construction allows a program to detect and deal with errors in a managed way.

A program should only raise an exception when something exceptional has occurred. Errors that are to be expected in the normal running of the program (such as invalid user input or network failures) should not be managed using exceptions.

A JavaScript class lets a programmer design the contents of an object by specifying data to be used in the class constructor method to set initial values of properties in the class.

A JavaScript class constructor method accepts parameters that can be used to initialize properties in a newly created class instance.

The JavaScript new keyword is used to create a new instance of a class by calling a constructor method in that class. Because missing method arguments to a JavaScript method call are replaced by the value undefined you can use a constructor call with no parameters to create an “empty” class instance that contains undefined values for all the properties.

A JavaScript class can contain methods that are members of the class. A member method can be called by code outside the class to allow an object to provide behaviors for that code.

Within a class method the reference this refers to the object within which the method is running.

JavaScript inheritance allows the creation of “super” or “parent” classes that can be extended to create “sub” or “child” classes. A subclass contains all the members of the parent. This allows attributes shared by a number of related classes to be stored in a single superclass.

A subclass can override methods in the superclass by providing their own implementations of the method. The keyword super allows a method in a subclass to call the superclass. The constructor of a subclass must contain a constructor method that makes use of the super mechanism to initialize the properties of the superclass.

A class can contain static data and method members which are stored as part of the class rather than being part of any instance of a class. A static method is a way that class can provide a behavior or data property that can be used without the need to create an instance of the enclosing class.

Here are some questions that you might like to ponder about what we have learned in this chapter:

What happens if a JavaScript program doesn’t catch an exception that has been thrown?

If an exception is thrown in some JavaScript that is not part of a try-catch construction the exception will be caught by the browser and the execution sequence will end. If you have the Developer View open, you will see the exception displayed in the form of a red error message.

When should a JavaScript program throw an exception?

Exceptions should only be used in exceptional circumstances. Some JavaScript functions, for example JSON.parse, use exceptions to signal error conditions. You can also make your code generate exceptions. When you start work on a project you need to decide on all the possible error conditions and then decide how each should be handled. Exceptions are useful because they provide a way that a low-level failure can be quickly propagated to a higher-level error handler.

Must my JavaScript programs catch all exceptions?

No. For me, the biggest concern when I write a program is not that the program might fail. It is that the user might think that it has worked when it has not. If an application fails with an obvious error, the user will get upset. If an application “pretends” that it has worked and the user later finds out that they have lost all their data, they will get very upset. You should ensure that exceptions are logged and reported in a way that makes their error reports useful.

Do I have to use classes in my programs?

No. However, they can make some kinds of programs (particularly those that need to deal with different types of related data) easier to write.

Can a JavaScript class have multiple constructors?

No. Some programming languages have a mechanism called “overloading” where a class can contain multiple versions of a method that all share the same name but have different parameters. JavaScript does not support overloading, so a class can only contain a single constructor method. If you want to provide different ways to construct an object, you must write code in the constructor method to decide what the parameters to the function mean.

What is the difference between a method and a function?

A method is declared as part of a class, whereas a function is declared outside any class. Both can accept parameters and return a result.

Can the this reference be used as an argument to a function call?

Yes. Within a method, the this reference refers to the object that the method is running within. If an object wants to send another object a reference to itself, it can pass the value of this as a function argument. This is like me calling you on the phone and telling you my phone number.

Can I use the this reference inside a static method?

No. A static method is a member of the enclosing class and is not associated with an existing instance.

11
Creating applications

What you will learn

In this chapter, we are going to make some applications. We are going to discover how JavaScript programs can work with functions to control how data is processed and then move on to consider how JavaScript applications can fetch services from the Internet. Finally, we’ll use the Node.js platform to create a JavaScript-powered web server of our own and build an application that can consume services from it. At the end of this chapter, you will know how web applications really work and how to build one of your own.

Data analysis

Create extra Fashion Shop functions

Read the weather

Node.js

Install and test Node.js

Deploying a Node.js server

What you have learned

Data analysis

We are going to start off by performing some analysis for the Fashion Shop application that we created in Chapter 10. This will allow us to explore some advanced features of JavaScript functions and discover how easy it is to perform analysis of the contents of arrays of data. We are going start by considering how a JavaScript program can display a list of items.

Fashion Shop stock list

At the end of Chapter 10, we had created an application to manage the stock in a Fashion Shop. The shop contains a variety of different stock items, each of which is represented by an instance of a particular object. The entire stock is stored as an array of stock items. One of the features of the application lets the user see all the stock in the shop in one long list (Figure 11-1). Now we are going to explore how this works.

Figure 11-1 Fashion Shop stock list

The Fashion Shop application produces a stock list, as shown in Figure 11-1. Each stock item is displayed on a line of text. The item details on each line of the list are preceded by an Update button that can be pressed to update the stock details for that item. Let’s look at how the stock list is produced. When the user presses the button to produce the stock list, the following JavaScript function runs:

Click here to view code image

function doListFashionShop() {
    createListPage("Stock List", dataStore);
}

The function doListFashionShop calls the function createListPage. The createListPage function is provided with two arguments. The first argument is the heading for the list. In this case, the heading is “Stock List.” The second argument is the list of items to be displayed. In this case, the program is listing the entire contents of the data store. The function createListPage creates the list page and displays it. Let’s have a look at how that works.

The source code to list the contents by using createList function. The line, openPage(heading); displays the page with the requested heading. The line, for (let item of items) { checks for all the items in the list. The line, let itemPar equals createListElement(item); creates a list of elements for an item. The line, mainPage.appendChild(itemPar); appends the list item to the main page.

The function createList works through all the list items and calls the function createListElement for each one. The list element that createListElement returns is then added to the mainPage. The mainPage variable is the HTML element in the document that the browser is displaying. It is how the Fashion Shop application displays data to the user. The final thing we need to look at is the createListElement function, so let’s see how that works.

The screenshot displays the createListElement function. The line, let resultPar equals document.createElement("p"); creates an enclosing paragraph. The line, let openButton = document.createElement("button"); creates the update button. The line, openButton.innerText equals "Update"; sets the update button text to "update." The line, openButton.className equals "itemButton"; sets the style sheet for the button. The line, let editFunctionCall equals "doUpdateItem('" plus item.stockRef plus "')"; creates a function call for the button click event. The line, openButton.setAttribute("onclick", editFunctionCall); add the onclick event to the button. The line, resultPar.appendChild(openButton); adds the button to the paragraph. The line, let detailsElement equals document.createElement("p"); creates the details paragraph. The line, detailsElement.innerText equals item.getDescription(); gets the item description and add it to the details. The line, detailsElement.className equals "itemList"; sets the style sheet for the description. The line, resultPar.appendChild(detailsElement); adds the description to the paragraph. The line, return resultPar; returns the created paragraph.

The output from this function is an element that is used to display the item in the HTML document for the Fashion Shop application.

Click here to view code image

<p><button class="itemButton" onclick="doUpdateItem('4')">Update</button>
<p class="itemList">Ref:4 Price:10 Stock:14 Description:red plain dress
                    Color:red Pattern:plain<ic:ccc> Size:14</p></p>

This is the HTML produced by createListElement for one of the stock items. The HTML includes a button that will call the doUpdateItem function when the button is clicked. The call of the doUpdateItem function is given an argument, which is the stockRef of the item being displayed. In the above HTML, the element with stockRef 4 is being displayed. The doUpdateItem function finds the requested element and displays it for update.

Fashion Shop data analysis

Imogen has found the Fashion Shop application very useful. She especially likes the stock list feature. Now she would like to add some more data analysis features:

A list of items in sorted in order of the number in stock so that she can quickly discover which items are running low

A list of items sorted in descending order of price so that she can identify expensive items that might be worth discounting

A list of items sorted in order of “investment” (price times number of stock items) so that she can identify where she has spent the most money

A list of just the items that have zero stock

The total value of all her stock

You decide to implement this by adding a Data Analysis option to the main menu for the program, as shown in Figure 11-2.

When Imogen clicks the Analysis button, the application will display a list of analysis commands, as shown in Figure 11-3.

This is our first “submenu” in the application. We could have put all the data analysis functions on the same page as all the other functions, but I think it the program is easier to use if some of the less-popular functions are placed on a different menu. We can create the menus just by creating the schemas for each one as we did in Chapter 10 in the “Build a user interface” section. We can then go back and fill in the functions that are required. Imogen can approve our “empty” menus before we write the code that makes them work.

Figure 11-2 Fashion Shop data analysis

The fashion shop data analysis application design is presented. The title, Imogen's fashion with a dress icon on the left is displayed at the top. The main menu lists the following with a corresponding button each mentioned inside parentheses: Add dress (dress), add pants (pants), add skirt (skirt), add top (top), update stock item (update), list stock items (list), and data analysis (analysis).

Figure 11-3 Fashion Shop Data Analysis menu

The fashion shop data analysis application design is presented. The title, Imogen's fashion with a dress icon on the left is displayed at the top. The data analysis lists the following with a corresponding button each mentioned inside parentheses: order by stock level (stock level), order by price (price), order by investment (investment), zero stock items (zero), total stock value (total), and return to main menu (main menu).

Work with array methods

The first three functions requested from Imogen involve sorting the stock data. The items in the Fashion Shop data storage are held in the order that they were added. To meet the first requirement, we want to sort the dataStore array in order of stock level. Sorting is something that a lot of programs need to do, so the JavaScript array type provides a sort method that we can use to sort the array. We just have to tell the sort method how to decide the order of elements during the sort.

We do this by providing a comparison function that compares two values and returns a result that indicates their order. If the result is negative, it means that the first value is “smaller” than the second. If the result is positive, it means that the first value is “larger” than the second. If the result is zero, it means that the two values are the same. We can generate a stock level comparison return value by subtracting one stock level from another.

Click here to view code image

function stockOrderCompare(a,b){
    return a.stockLevel-b.stockLevel;
}

The function stockOrderCompare takes in two parameters. It gets the stock level values from each item and then returns the result of subtracting one stock level from another. This comparison function can be provided as an argument to the call of the sort method to get the dataStore sorted in this order.

Click here to view code image

dataStore.sort(stockOrderCompare);

We don’t need to know how the sort method sorts the dataStore any more than we need to know how JavaScript adds two numbers together. One thing that it is useful to know, however, is that the sorting process will not move any StockItem values around in memory. The datastore contains an array of references. We can change the order of the references without having to move anything in memory.

Click here to view code image

function stockOrderCompare(a, b) {
    return a.stockLevel - b.stockLevel;
}

function doListStockLevel() {
    dataStore.sort(stockOrderCompare);
    createList("Stock Level Order", dataStore);
}

This is the code that produces a list of stock item sorted by stock level. The function doListStockLevel above is called when Imogen selects the option to display the stock sorted in the order of stock level. It sorts the dataStore array and then uses the createList function to display the sorted list.

CODE ANALYSIS

Sorting stock items

The Fashion Shop application in the Ch11 Creating Applications\Ch11-01 Fashion Shop Stock Sort example folder contains the analysis feature that can be used to display a list of stock items that have been sorted by stock level. You might have some questions about how it works.

Question: What happens when we use the stockItemCompare function as an argument to the sort method?

Answer: A JavaScript function is an object, like lots of other things in JavaScript programs. Objects are managed by references, so the sort method receives a parameter, which is a reference to the stockItemCompare function.

Question: What happens if we try to use the stockItemCompare function on a list of objects that don’t have stockLevel properties?

Click here to view code image

var names = ["fred", "jim", "ethel"];
names.sort(stockOrderCompare)

Answer: The JavaScript above shows how we would this. The first statement creates an array of strings, which is called names. The seconds statement tries to sort the names using stockOrderCompare as the comparison function. This will not work because the strings in the names array do not have a stockLevel property, but what would it do?

We can work out what would happen by considering what JavaScript does when things go wrong. If we try to access a nonexistent property in an object, JavaScript returns a value of undefined. This means that the stockOrderCompare function would be comparing two undefined values. The result of any calculation involving undefined is the Not a Number (NaN) value. This means that the comparison function returns NaN, which is ignored by the sort method, leaving the array unchanged.

Question: How would I sort an array of names?

Answer: We would have to create a comparison function that compares two strings and returns the required result. JavaScript expressions can be used to determine if one string is “greater than” (further down the alphabet) than another. We can make a stringOrderCompare function.

The JavaScript code of the function stringOrderCompare is presented. The function has two parameters a and b. The line of code, if (a less than b) return negative 1 represents a less than b. The line of code, if (b less than a) return 1 represents b less than a. The line of code, return 0 represents both strings the same.

This function can be used to sort the name array we created earlier. The stringOrderCompare function is declared within the Ch11 Creating Applications\Ch11-01 Fashion Shop Stock Sort example.

Click here to view code image

> names.sort(stringOrderCompare)
 ["ethel", "fred", "jim"]

Anonymous functions

We can control how sort behaves by changing the function that is used to perform the comparison, but it is rather unwieldly to have to create the function and then use it as an argument to the call of sort. JavaScript makes it easier to do this by allowing us to declare the comparison function directly in the arguments of the sort call:

Click here to view code image

dataStore.sort(function(a,b){
    return a.stockLevel-b.stockLevel;
});

This sort does the same job as the original one, but the comparison function is provided as an argument to the call of sort. This type of function declaration is called an anonymous function because it has no name. The function can’t be called by any other code. It has the double advantage of making the program slightly smaller and also binding the comparison directly to the call of sort. With the above code, you don’t have to go and find out what the stockOrderCompare function does. The application in the Ch11 Creating Applications\Ch11-02 Fashion Shop Simple Function example folder uses this simplified function format to control the sort behavior.

Arrow functions

Arrow functions are a way of making programs even faster to write. Rather than having to type function to create an anonymous function, you can express the function like this:

Click here to view code image

dataStore.sort((a,b) => { return a.stockLevel - b.stockLevel});

The parameters to the function are given before the arrow (=>), and the block of statements that make up the body of the function is given after the arrow. If your function contains only one statement, you can dispense with both the statement block and the return keyword to make a very short arrow function:

Click here to view code image

dataStore.sort((a,b) =>  a.stockLevel - b.stockLevel);

The statement above would sort the datastore in ascending order with the lowest stock levels first. What change do you think you would have to make to sort in descending order?

Click here to view code image

dataStore.sort((a,b) =>  b.stockLevel - a.stockLevel);

This turns out to be a very small change to the program. We just have to reverse the order of the subtraction, as shown in the statement above.

CODE ANALYSIS

Anonymous functions

Anonymous functions and arrow functions are very powerful JavaScript features, but they are also rather confusing when you first see them.

Question: Why is an anonymous function called “anonymous”?

Answer: Because it has no name. Up until now, all the functions and methods that we’ve created have been given names so that we can refer to them in other parts of the program. However, with an anonymous function, I just want to describe a particular behavior to be performed at one point in the program. I could give the behavior a name (as in stringOrderCompare) above, but it is much easier if I can just drop the JavaScript code directly into my application at the point where I want to use it. Programmers sometimes call anonymous functions lambda functions.

Question: Can I call an anonymous function from a different part of my application?

Answer: No. The only place that the code in an anonymous function can be used is the point when it is declared. It can’t be accessed anywhere else because it has no name.

Question: Can an anonymous function call other functions?

Answer: If you wanted to, you could write an anonymous function containing many thousands of lines of code. However, I would not recommend this. I see anonymous functions as just offering a way of dropping a small piece of specific code into a program.

Question: Can I use an anonymous function as an argument to a function?

Answer: Yes, you can. In JavaScript, a function is an object like anything else and can be passed around a program like any other value. In fact, we have already done this. When we use sort, we pass it a function that is to be used to compare two values to be sorted.

Question: Is there any difference between an anonymous function created using the keyword function and one created using the arrow notation?

Answer: We have seen that there are two ways we can describe an anonymous function:

Click here to view code image

dataStore.sort(function(a,b){
    return a.stockLevel-b.stockLevel;
});

This version makes an anonymous function to perform the comparison in a sort operation. The anonymous function is supplied as an argument to the sort method.

Click here to view code image

dataStore.sort((a,b) => { return a.stockLevel - b.stockLevel});

This version uses an arrow function to perform the same task. For the task above, you can use function or arrow interchangeably. However, there are differences between how the two anonymous functions work. The most important one is the way that the keyword this works inside an anonymous function. We know about this because we’ve used it to access elements of an object from methods running inside the object. If you want to write an anonymous function that makes use of this to get hold of elements in an enclosing object, you must use the arrow function notation to create the anonymous function. When you use the word function to make an anonymous function, you create a new object that the function code runs inside. Code running inside this kind of anonymous function can only access elements declared inside that function body, which is not usually what you want.

However, code running in the body of an anonymous function created using the arrow notation picks up the value of this from the enclosing object, so the code can get hold of properties from the object. All this is rather complicated, so suffice it to say that if you had an anonymous function running inside a Dress object, and you wanted that function to be able to get hold of the size property of the dress, you should use arrow notation to create the anonymous function.

Sorting by price and value

Sorting in order of price (which is the second data analysis that Imogen wants) can be achieved by changing the comparison function to compare two stock items by their price properties:

The doListPrice function is a slightly modified version of the doListStockItem function. The final sorting command, which sorts by the amount invested in each type of stock, is slightly more complex because the comparison function needs to work out the total value of each stock item. This value will be the price of an item multiplied by its stock level.

Click here to view code image

function doListInvestment() {
    dataStore.sort((a,b) =>  (b.price * b.stockLevel) - (a.price * a.stockLevel));
    createList("Investment Order", dataStore);
}

The application in the Ch11 Creating Applications\Ch11-02 Fashion Shop All Sorts folder contains a version of the Fashion Shop application that implements the sorting behavior using arrow functions.

Use filter to get items with zero stock

The next thing that Imogen wants is a feature that lists all the stock items that have zero stock. We could create a for-loop that will work through the dataStore array and pick out all the items with a stockLevel value of 0. However, there is a much easier way to do this by using another method provided by the array object. We have seen that all arrays provide a sort method that can be used to sort their contents on the basis of a particular comparison function. Arrays also provide other useful methods, including one called filter that works through an array, applying a function that tests each element in the array. If the test evaluates to true, the array element is added to the result.

I’ve written the test as an arrow function that accepts a stockItem (which is what is in the array) and returns true if the stockLevel property of the item is zero. The filter function returns a list that is then displayed by the createList function. As with stockLevel, the zeroStockList contains references to stock items, not the items themselves. The Ch11 Creating Applications\Ch11-03 Fashion Shop Filter example folder holds a version of the Fashion Shop application that will list the stock items with zero stock levels. We can use this technique to filter the list on any criteria that we like by simply changing the behavior of the selection function.

Use reduce to calculate the total value of the stock

The next feature that Imogen wants is the ability to calculate the total value of all her stock. We could create a for-of loop that works through the datastore array, but there is an easier way to do this by using the reduce method provided by arrays. The reduce method reduces the content of an array to a single value by performing a reduce function on each element in the array and adding up all the results. To make things clearer, I’ll start with a named function before converting it into an arrow function.

Click here to view code image

function addValueToTotal(total,item){
    return total+(item.stockLevel*item.price);
}

The function addValueToTotal accepts the current total as the first parameter and a reference to a stock item as the second parameter. It calculates the value of the stock item, adds this to the total, and then returns the result. We can use the reduce method in the dataStore array to apply this function to every element in the stock list and work out the total value of the stock:

Click here to view code image

var total=dataStore.reduce(addValueToTotal, 0);

The first argument to the reduce method is the function that will be called to update the total. The second parameter is the initial total value, in this case, zero. We can convert the addValueToTotal function into an arrow function, in which case, the call of reduce looks like this:

Click here to view code image

var total = dataStore.reduce(
    (total, item) => total + (item.stockLevel * item.price),
    0);

The application in the Ch11 Creating Applications\Ch11-04 Fashion Shop Total Value example folder displays the total value of the stock. You can select Total from the Data Analysis menu, and the function displays an alert containing the total stock value. Note that because this program generates new test data each time it is started, you will find that the total value changes each time it is run.

Use map to discount all stock items

You give Imogen the completed version of the software and she is very happy with it—for a while. Then she comes back with another request. She would like to be able to apply a discount to all the items in stock. She would like to be able to drop all the prices by 5 percent. You could do this with a for loop that works through the array, but an array provides a function called map that will apply a given function to every element in the array. To apply a 5 percent discount, you can multiply the price by 0.95.

Click here to view code image

dataStore.map((item)=>item.price = item.price*0.95);

This single statement will do the job. The map method accepts a function that has a single parameter. The parameter is the item to be worked on. The statement above will drop the price of every item in stock by 5 percent. You can find this example program in the Ch11 Creating Applications\Ch11-05 Fashion Shop Discount folder.

MAKE SOMETHING HAPPEN

Create extra Fashion Shop functions

Now that you know how to use the map, filter, and reduce methods, you could add some other functions that Imogen might like. Note that for some of them, you might have to use more than one method to achieve the requested result.

Add a command that removes a 5 percent discount. (Note that this does not mean that you would add 5 percent to all the prices; you will have to add more than that because the price has been discounted.)

Add a command that reduces the price of all items that cost more than $50 by $5. In other words, a dress costing $20 would stay the same price, but a dress costing $60 would be reduced to $55.

Add a command that displays the number of items in stock that are colored red.

Read the weather

In this section, we are going to discover how JavaScript programs can fetch and use data from the Internet. You can use this technique to fetch data from a huge range of sources. We are going to create an application that reads weather information from the OpenWeather service at https://openweathermap.org. It is free to create an account on the OpenWeather site and use it to make a limited number of weather requests each day. I’ve also created some “fixed” weather data on the GitHub site for this book that you can use to test your program if you don’t want to register. The weather information is supplied as a JSON-encoded object that arrives in a string of text. The first thing we must investigate is how to fetch a string of text from a server on the Internet.

Fetch data from a server

Until now, all the actions performed by our JavaScript programs have completed very quickly. However, it can sometimes take a while for information to arrive from the Internet, and sometimes a network request can fail completely. A JavaScript application that uses a network connection will have to deal with slow responses and the possibility that a request might fail. A good way to do this is to make the fetch process asynchronous.

Asynchronous operation

There are two ways that I can go shopping. I can go to a shop, select what I want, pay for it, and take it home. My actions are synchronized with the shop because I must wait for the sales assistant to accept my payment and hand over the goods before the shopping is completed. Alternatively, I can email my shopping list to the shop and ask them to deliver my purchases. Now I can do other things, such as dig in the garden while I wait for my shopping to arrive. My actions are not synchronized with the shop, meaning they are asynchronous. If the shop takes a long time to deliver, it just means that I might have more time for gardening (which is actually not a win for me as it turns out—I’d rather stand in a shop than work in the garden). Up until now, when a JavaScript program has asked for something to be done, the action has been performed synchronously. For example, consider this statement.

Click here to view code image

descriptionPar = document.createElement("p");

This statement is from the Fashion Shop application. It calls the createElement method to create a new document element. When this statement is performed, the application waits for the createElement method to deliver a new document element in the same way that I wait in a shop for my shopping. The createElement method runs very quickly, so the application is not kept waiting long. However, a function that uses a network connection to fetch data from a distant server could take several seconds to complete. This would pause the application for several seconds. The user would not be able to click any buttons on the screen for that time because the browser only allows a JavaScript application to perform one action at once. If you’ve ever had the experience of a web page “locking up” when you try to use it, you will know how bad this feels.

JavaScript promise

To get around this problem, JavaScript introduces the idea of promises. A promise is an object that is associated with a task that a program wants to perform. JavaScript provides a method called fetch, which is used to fetch data from a server. However, the fetch function does not return the data; instead, it returns a promise to deliver the data at some point in the future.

Click here to view code image

var fetchPromise = fetch('https://www.begintocodewithjavascript.com/weather.html');

The statement above uses fetch to fetch the contents of the file at 'https://www.begintocodewithjavascript.com/weather.html'. This call of fetch returns a promise object. The variable fetchPromise refers to this object. The fetch will start to happen asynchronously. You can think of this as the point in the process where I call the shop and ask them to deliver my shopping.

The fetchPromise object is a link between our application that requested the data and the asynchronous process fetching the data. We set a property on a promise object to identify a function to be called when the promise is kept. A promise object provides a method called then, which accepts a reference to the method to be called when the promise has been kept.

Click here to view code image

fetchPromise.then(doGotWeatherResponse);

The statement above tells fetchPromise to call the function doGotWeatherResponse when it has finished fetching. So now we need to find out what the doGotWeatherResponse function does.

The JavaScript code of the function doGotWeatherResponse is presented with a parameter called response. The line of code inside the function, if (!response.ok) left brace check to see if the request succeeded. The line of code, alert ("fetch failed") displays an alert if the request failed. The line of code inside the function, jsonPromise equals response.json gets another promise to decode the JSON in the response. The lien of code, jsonPromise.then(doGotWeatherObject) calls doGotWeatherObject when the JSON is decoded.

The parameter to a function called when a promise is kept is the result delivered by that promise. In the case of fetch, the parameter is a response object that describes what happened when it tried to fetch the data. It is possible that a network request can fail, so the first thing that the doGotWeatherResponse function does is check the ok property of the response. If this is false, an alert is displayed and the function ends.

If the response is ok, the doGotWeatherResponse function starts the process of getting the data. It uses a “promise-powered” process to obtain the JavaScript object from the JSON in the response.

Get JSON from the network

The json method provided by the response will get the text from the network and convert it from JSON into a JavaScript object. This might take some time. There might be a lot of data to be fetched and decoded, so it makes sense that this process is performed asynchronously, too. The then method of the JSON promise is used to nominate a method called doGotWeatherObject to be called when the weather object has been created from the network.

Click here to view code image

function doGotWeatherObject (weather) {
  let resultParagraph = document.getElementById('resultParagraph');
  resultParagraph.innerText = "Temp: "+ weather.main.temp;
}

The doGotWeatherObject function gets the temperature information from the weather object and displays it in a paragraph on the page.

Click here to view code image

{"coord":{"lon":-0.34,"lat":53.74},
 "weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04d"}],
 "base":"stations",
 "main":{"temp":18.14,"feels_like":17.24,"temp_min":18,"temp_max":18.33,
         "pressure":1019,"humidity":82},
 "visibility":10000,"wind":{"speed":3.6,"deg":270},
 "clouds":{"all":98},"dt":1599639962,
 "sys":{"type":1,"id":1515,"country":"GB","sunrise":1599629093,"sunset":1599676358},
 "timezone":3600,"id":2645425,"name":"Hull","cod":200}

This is the JSON that describes the weather. You can see that the object contains a main property that contains a temp property that is the temperature value. Note that the temperature is delivered as a value in degrees Celsius, not Fahrenheit. The application in the Ch11 Creating Applications\Ch11-06 Weather Display example folder contains these functions and will display the weather information when the FETCH button (shown in Figure 11-4) is pressed.

Figure 11-4 Weather display

The weather display application is presented on a browser screen. The weather is displayed on a black background. The title weather with an umbrella icon on the left is displayed on the top. The temperature is displayed as, temp: 18.14. The fetch button is displayed at the bottom.

Use anonymous functions to simplify promises

The code we have just written will work perfectly well and shows how functions are bound to promises. However, it is also rather long-winded. It turns out that we can use anonymous functions to simplify the code a lot. We can express an anonymous function using the arrow notation. Take a look the “Arrow functions” section above if you want to refresh your understanding of how they work. In this code, we are going to use an arrow function to specify actions to be performed when a promise is fulfilled.

The JavaScript code of the function doGetWeather is displayed. The line of code, fetch (url).then(response implies left brace represents the function that runs when the response is complete. The line of code response.json().then(weather implies left brace represents a function that runs when JSON decoding is complete.

The doGetWeather function accepts a parameter that gives the network address of the item to be loaded. The function has exactly the same logic as our previous implementation. However, the functions that are to run when the promises are fulfilled are now written as arrow functions that are given as parameters to then. You can find a weather application that uses this function in the Ch11 Creating Applications\Ch11-07 Weather Arrow Functions sample folder. You can use this code to read JSON objects from different locations by changing the URL string.

Get text from the network

If you just want to read the text from a website rather than the JSON, you can use the text method, which returns a promise to deliver text rather than a JavaScript object. You can see this in use in the application in the Ch11 Creating Applications\Ch11-08 Weather Text sample folder.

Handle errors in promises

In JavaScript, as in real life, it can sometimes be impossible to fulfil a promise. Perhaps the network is broken, or the text delivered by the server does not contain a valid JSON string. In these situations, the promise will not fulfill by calling the function nominated by then. Instead, a promise can call an error-handling function that has been nominated by a call to the catch method of a promise. The catch function is used in exactly the same way as the then function. It accepts a parameter that describes the error that has occurred.

Click here to view code image

function doGetWeather(url) {
  fetch(url).then( response => {
    if(!response.ok){
      alert("Fetch failed");
      return;
    }
    response.json().then( weather => {
      let resultParagraph = document.getElementById('resultParagraph');
      resultParagraph.innerText = "Temp: " + weather.main.temp;
    }).catch ( error => alert("Bad JSON: " + error)); // json error handler
  }).catch( error => alert("Bad fetch: " + error)); // fetch error handler
}

You can see the two catches in the doGetWeather function above. They display an alert that contains any error message that was produced when the promise failed.

Use finally to enable a button after a fetch

The weather application we have created makes a fetch request each time the FETCH button is clicked. This can lead to problems. One thing that users quite like to do is repeatedly click a button if they don’t get a response within a second of their first click. In the weather application, this would cause lots of fetch requests. A well-written application would disable the FETCH button once it has been clicked to prevent this behavior. So let’s make our application well-written. A JavaScript program can disable a button by adding a disabled attribute to the button:

These two statements disable a button with the ID fetchButton. Once the fetch has completed, the program can enable the button. We could add code to the then and catch functions to enable the button, but as you know, I hate writing the same code twice. Instead, we can add a finally function to a promise that identifies code to run when the promise has completed, regardless of whether it succeeds. This would guarantee that the FETCH button is enabled once the fetch is complete.

The JavaScript code for removing the disabled attribute is presented. The line of code, let fetchButton equals document.getElementById('fetchButton') finds the button. The line of code, fetchButton.removeAttribute("disabled") removes the disabled attribute.

This is the code that I added to remove the disabled attribute from the FETCH button. You can find it in the sample application in the Ch11 Creating Applications\Ch11-09 Weather Finally example folder.

CODE ANALYSIS

Investigating promises

The application in the Ch11 Creating Applications\Ch11-10 Weather Error Handling example folder uses the doGetWeather function above to display the temperature. It also contains two other buttons that activate two broken fetch behaviors. The first attempts to load the weather from a nonexistent network address, and the second loads a file that does not contain JSON data. You can use these to experiment with failed promises.

Question: What does a promise do again?

Answer: If this is confusing, think of the problem that it is trying to solve. Our program wants to get some information from the network that would take a long time to arrive. So rather than call a method that delivers the information, it calls a method that delivers a promise to perform the action. In other words, rather than saying, “Give me the data from the network,” we say, “Give me a promise object that will be fulfilled when the data has been fetched from the network.”

An application can attach functions to a promise object to be called when the promise is fulfilled (then) or broken (catch). Our program can then continue running without having to wait for the data to arrive. The actions required to deliver on the promise will be performed asynchronously, and at some point in the future, the promise will either be kept or broken, and one of the functions called.

Question: Can I have two promises active at the same time?

Answer: Yes, you can. If you click the FETCH ERROR button in the example above, you will notice that it takes several seconds for the error message to appear. While you are waiting for the error, you can click the FETCH and JSON ERROR buttons to perform their fetch behaviors.

Question: Can I write code of my own that implements promises?

Answer: Yes, you can. We will be doing this in the next chapter when we create a promise that is fulfilled when an image has been loaded into our game.

Question: Why do I need to create a catch behavior for the fetch promise? Can’t I enclose the call of fetch in a try-catch construction to catch any errors that are thrown by fetch?

Answer: If you understand this question and the answer, you can consider yourself a “promise ninja.” JavaScript code can throw an error object when things get tough. This is called an exception. We’ve seen that code working with JSON throws exceptions if it can’t convert a string into a JavaScript object. Look in Chapter 10 in the section “Catching exceptions” to find out how this works. You might think that we could just put a call of fetch inside a try-catch construction in our application to pick up any errors when they occur.

Click here to view code image

try{
  fetch(url).then( response => {
  // rest of fetch code here
}
catch{
  // handler for errors during fetching
}

The code above shows what you might try to do. However, this would not work because the fetch function only starts the process of fetching network data. Once the process of fetching begins, the fetch function completes, and the application continues out of the enclosing try-catch construction. Errors that arise while getting the data from the server can’t be handled by a try-catch around fetch because the program execution will have left the try-catch block long before the exception is raised.

Question: When would I use finally?

Answer: You use finally when you want to nominate a behavior that must be performed once the promise has ended (by being either fulfilled or broken). This might be to enable a button (which is what we have done) or to tidy up resources that were obtained when the promise started. It is a good idea to get into the habit of using finally, as it is guaranteed to run at the end of the promise, even if code in then or catch functions fail in ways you weren’t expecting.

Node.js

Up until now, all the JavaScript applications that we have written have run inside the browser and used the HTML document to interact with the user. This is fine for creating client applications (meaning applications that fetch data and work with it), but it would be useful to be able to create JavaScript applications that could work as servers that provide data for client applications. In this section, we are going to discover how to use a platform called Node.js to create a server application written in JavaScript. Node.js was created by taking the JavaScript component out of a browser and making it into a freestanding application that can host JavaScript code.

MAKE SOMETHING HAPPEN

Install and test Node.js

Before we can use Node.js, we need to install it on our machine. The application is free. There are versions for Windows PC, macOS, and Linux. Open your browser and go to https://nodejs.org/en/download/.

The installer window of the node js application is presented. The versions of LTS (recommended for most users) and current (latest features) are displayed for download where LTS is selected. The windows installer, macOS installer, and source code are displayed. The packages of the application are available for download for different OS versions.

Click the installer for your machine and go through the installation process. Once you have completed the installation, you can start to work with Node.js. The first thing you can do is test that the installation has worked correctly. We can do that by using the terminal in Visual Studio Code. Start Visual Studio Code, open the View menu, and select Terminal. The terminal window will open in the bottom right-hand corner of Visual Studio Code. You use this window to send commands to the operating system of your computer. I’m using a Windows PC, so my commands will be performed by Windows PowerShell. Enter the command node and press Enter.

The Node application starts and displays a command prompt. You should find this remarkably familiar. If you enter a JavaScript command, it will be obeyed in the same way as if you were using the console in the Developer View in your browser.

You can exit from the Node.js command prompt by holding down the CTRL key and pressing D.

The Node.js application provides a way for a computer to run JavaScript applications. If you had entered the command node myprog.js, the command prompt would have executed the JavaScript program in the myprog.js file. Note that because this application is not running in a browser, it can’t use an HTML document to communicate with the user. In other words, Node.js applications can’t use buttons, paragraphs, and all the other elements because there is nowhere for them to be displayed. The job of Node.js applications is to host processes that provide services. It is perfectly possible that the weather service that we have just used is hosted by a Node.js application running on a server connected to the Internet.

Create a web server with Node.js

In Chapter 2 in the “HTML and the World Wide Web” section, we discovered that a web browser uses the HTTP protocol to fetch data from web servers. HTTP describes a way that one program (the browser) can ask for resources from another program (the server). A web server is an application that receives HTTP-formatted requests and generates responses.

Use the HTTP module

The Node.js platform is supplied with a module containing a JavaScript program that can respond to HTTP requests and act as a web server. A module is a package of JavaScript code that we want to use. We can include a module in our application by using the require function to load it. The module is then exposed as an object. The application using the module will then call methods on that object.

var http = require('http');

This statement above creates a variable called http, which refers to an HTTP instance. Now we can use the HTTP object to create a web server. We can do this by calling the createServer method:

The JavaScript code for calling the createServer function is presented. The line of code, var server equals http.createServer((request, response) implies left brace calls the createServer function. The line, response.statusCode equals 200 sets the status code for the response. The line, response.setHeader('content type', 'text/plain') defines the content type in the response header. The line, response.write('hello from simple server') sends the content of the response. The line, response.end() ends the response and sends it.

The statement above uses the createServer method supplied by the http object to create a simple web server. The variable server is set to refer to the new server. The createServer method accepts a single argument, which is an arrow function that works on two parameters. This function provides the behavior of the server. It will be called each time a client makes a request of the server. The first parameter to the function describes the request that has been received. The second parameter will hold the response that is to be produced. Our server behavior is implemented by an arrow function that accepts the parameters request and response. The function above ignores the contents of the request and just prepares a response that is a text message 'Hello from Simple Server'. Now that we have our server object, we can make it listen for incoming requests.

server.listen(8080);

The listen method starts the server listening for incoming requests. The listen method is supplied with an argument specifying the port that the server will listen on. Each computer on the Internet can expose a set of numbered ports that other computers can connect to. When a program connects to a machine, it specifies a port that it wants to use. Port number 80 has been set aside for HTTP access, and browsers will use this port unless told otherwise. Our server will listen on port 8080.

CODE ANALYSIS

Using a server

You can find this sample server application in the examples for this chapter. We will not be using this application from the browser; we will start the server running from within Visual Studio code and then view the page that it generates with a browser. Start by opening the Visual Studio Code application and then open simpleServer.js in the Ch11 Creating Applications\Ch11-11 HTML Server example folder, as shown below:

To start the server, you need to run the program in simpleServer.js. Make sure that this file is selected in the file browser as shown above. Open the Run menu and select the Start Debugging option. There are several different ways that Visual Studio Code can run your application, so you will be asked to select the environment you want to use:

Click the Node.js option, and the server will start. Now you can open your browser and connect to this server. Because the server is running on your machine, you can use the Internet address localhost. You need to add the port number that you are using to this address, so enter the address localhost:8080 address into the browser and press Enter to open the site.

When you do this, you will see the message from the function that is running inside the server. You might have some questions about what you have just done:

Question: Would this server work on the Internet?

Answer: Yes. You are running both the server (the Node.js program) and the client (the browser) on your PC. However, you could run the server on one machine and access it from the browser on another. If the server machine were on the Internet, it would be possible for distant machines to access the server. One thing to bear in mind, however, is that modern operating systems include a firewall component to manage their network connections. The firewall limits the network services that one machine exposes to another in case malicious programs try to take advantage of too much connectivity. If you want to create a server and allow people access to it, you can use Node.js to do this, but you would have to configure the firewall on the host machine and also take steps to ensure that you provided the services in a secure way.

Question: Does the server program run forever?

Answer: Yes. The call to the listen method will never return. You can use Visual Studio Code to stop the program by clicking the red square box stop button on the right-hand side of the program controls.

Question: How is the response message from the server constructed?

Answer: The server creates a response object that is sent back to the client. The response tells the client if the server could satisfy the request and contains the data that was requested. The server application performs four statements to create and send the response that is received by the browser:

response.statusCode = 200;

The first statement sets the status code of the response. A status code of 200 tells the browser that the page was found correctly.

Click here to view code image

response.setHeader('Content-Type', 'text/plain');

The second statement adds an item to the response header by using the setHeader method. A response header can contain items to help the browser deal with the incoming response. Each item is provided as a name-value pair. This statement adds a Content-Type value that tells the browser that this response contains plain text. We could use different types to return things like audio files and images.

Click here to view code image

response.write('Hello from Simple Server');

The write method writes the content of the page being returned. This server always sends the same text: Hello from Simple Server. It could, instead, send a very large amount of data.

response.end();

The end method tells the server that it can now send the response and the content back to the browser client.

Routing in HTML

In the “Fetching web pages” section in Chapter 2, we saw that the URL expressing the location of a web page contains a host element (the Internet address of the server) and a path element (the path on the host to the item that the client wants to read). The simple server above returns the same text for any path that you use to read from the host. In other words, the URLs http://localhost:8080/index.html and http://localhost:8080/otherpage.html both return the message Hello from Simple Server, as would any other path. The first web server used the path component of a URL to identify the file that the server should open and send to the client. We can improve our simple web server to allow it to respond differently to different paths.

The JavaScript code is presented for routing in HTML. The line of code, var http equals require('http') uses the http object. The line, var url equals require('url') uses the url object. The function sendResponse(response, text) sends a response to the browser. The createServer function is called with the parameters request and response. The line of code inside the createServer function, var parsedUrl equals url.parse(request.url) parses the incoming response URL. The line of code inside the createServer function, var path equals parsedUrl.pathname gets the page path from the parsed URL. The switch statement, switch (path) switch on the path. The line inside the switch statement, case "/index.html" sends the response for index.html. The line inside the switch statement, case "/otherpage.html" sends the response for otherpage.html. The default case sends the response for any other path.

The code above implements a server that recognizes two paths: index.html and otherpage.html. If the client tries to access any other path, the sever responds with a “page not found” message. Note that the “page not found” message has a status code of 404 to represent this. The program parses the url property of the request parameter to extract the path that was requested in the URL. This path is then used to control a switch construction that selects the response to be sent. You can find this example server in the example folder. This server program could be expanded to serve a number of different pages.

CODE ANALYSIS

Using multiple paths

You can find the multiple page server in the Ch11 Creating Applications\Ch11-12 Multi page server example folder. Start Visual Studio Code and from the examples folder, open multiPageServer.js. Ensure that the multiPageServer.js file is selected in the file browser. Now click Run -> Start Debugging to start the application. Select the node.js environment when prompted by Visual Studio Code. Now open your browser and navigate to: http://localhost:8080/index.html.

The browser will show the text for this URL. Now change the address to http://localhost:8080/otherpage.html and reload the page.

The browser will now display the response for the other page. Finally, you can try a missing page. Change the address to http://localhost:8080/missingpage.html and reload.

If a given path is not recognized, the default element in the switch is performed. This displays the “page not found” message. You might have some questions about this code:

Question: What does the sendResponse function do?

Answer: I hate writing the same code twice. The sendResponse function sends a string as a response to a web request. It saves me from writing the same code to respond to the two different URL paths.

Question: How does the server get the path to the resource that the client has requested?

Answer: The URL is the entire address sent by the browser to the server to request a particular web page. The path part of a URL describes the location of a resource on the server. For example, the server might receive the URL http://robmiles.com/index.html. The path in this URL is /index.html. The URL that was given to the web request is provided as the url property of the response parameter to the method called by createServer. The method called by createServer must extract the path from this URL so that the server can decide what to send back to the browser. The server does this by using the URL module that was loaded at the start of the program.

var url = require('url');

The URL module provides methods that an application can use to work on URL strings. One of the methods that is provided is called parse. The word “parse” means “look through something and extract meaning from it.” The parse method accepts a URL string as an argument.

Click here to view code image

var parsedUrl = url.parse(request.url);

The parse method creates an object that exposes different parts of the URL as properties. The statement above creates a parsed URL object (called parsedUrl). I use parse because I am lazy and don’t want to have to write JavaScript that extracts the path from the URL string.

Click here to view code image

var path = parsedUrl.pathname;

Once we have a parsed version of the URL (called parsedUrl), we can extract data from the properties in this object. The pathname property of a parsed object gives the path that the user entered. The statement above gets the path name from the parsed URL and sets the variable path to this name. We are going to use parse again later in this chapter to extract other information from the URL.

Question: What would I need to do if I wanted to add extra “pages” to my server?

Answer: The present version of the server only recognizes the /index.html and /otherpage.html pages. If you want to add other pages such as /aboutpage.html, you just have to add another case to the switch:

Click here to view code image

case "/aboutpage.html":
  sendResponse(response, "hello from aboutpage.html");
  break;

The example program in the Ch11 Creating Applications\Ch11-13 Three page server folder serves three pages.

Question: Can I serve HTML pages using this server?

Answer: Yes, you can. However, you need to change the content type from text/plain to text/html so that the browser knows how to process the response.

Click here to view code image

response.setHeader('Content-Type', 'text/html');

The example program in the Ch11 Creating Applications\Ch11-14 HTML server folder serves an index page that is HTML.

Question: Is this how you build servers?

Answer: You could build server like this, but it would be hard work. Your server would also have to serve out the image and style sheet files along with the HTML files. I just want to show you how this works so that you can understand how servers work. The Express framework (which we will see later) provides a much quicker way of creating a JavaScript application that will act as a server. However, it uses the same fundamental principles that we have been using.

Use query to add data to a client request

A client can use different path values to select locations on a website, but it would also be useful for the client to be able to send additional data to the server. We can do this by adding a query string to the URL that is sent by the client to the server. You will often see query strings in your browser when you navigate e-commerce sites. A query string starts with a question mark (?) and is then followed by one or more name-value pairs that are separated by the ampersand (&) character:

Click here to view code image

http://localhost:8080/index.htm?no1=2&no2=3

The URL above contains two query values: no1 (set to the value 2) and no2 (set to the value 3). These query values are sent to the server in the URL string. We could create a server that accepted these values and returned their sum. The server could use the parse method from the url module to extract the query values.

Click here to view code image

var parsedUrl = url.parse(request.url,true);

We used the url.parse method in the previous section when we needed to extract the resource path from the incoming URL. The call of parse is different in that I’ve added the parameter true to the call, which tells the parse method to parse the query string in the URL.

var queries = parsedUrl.query;

Once I’ve done this, I can extract the value of the two queries from the parsedUr, as shown above. Now my addition program can convert these two query strings into numbers and perform the required calculation:

Click here to view code image

var no1 = Number(queries.no1);
var no2 = Number(queries.no2);

var result= no1 + no2;

The query values are always sent as strings of text. Our application uses the Number function to convert the query values into numbers. It then calculates their sum. The listing below is the complete source of an “addition” service, which accepts a query containing two numbers and returns their sum.

Click here to view code image

var http = require('http');
var url = require('url');

var server = http.createServer((request, response) => {

  var parsedUrl = url.parse(request.url,true);
  var queries = parsedUrl.query;

  var no1 = Number(queries.no1);
  var no2 = Number(queries.no2);

  var result= no1 + no2;

  response.writeHead(200, { 'Content-Type': 'text/plain' });
  response.write(String(result));
  response.end();

});

server.listen(8080);

The addition service that we created above does not produce a web page as a result. It returns a string that contains the result of adding two query values together. This kind of service is called a web service. It uses HTTP to transfer messages, but the messages do not contain HTML documents. A more complex web service could return an object described by a string of JSON. We’ve already used one web service, the weather service from openweather.org. Now we know how to create our own web services using JavaScript and Node.js to host them. A Node.js application could also use the file system module fs to open files held on the server and send them as responses.

CODE ANALYSIS

Investigate the addition server

You can find the addition server in the Ch11 Creating Applications\Ch11-15 Addition Server example folder. Start Visual Studio Code and open additionServer.js in the example folder. Ensure that the file additionServer.js is selected in the file browser. Now use Run -> Start Debugging to start the application. Select the node.js environment when prompted by Visual Studio Code. Now open your browser and navigate to http://localhost:8080/index.html?no1=2&no2=3.

The server program will work out the result of the calculation (2+3) and return the result. Try changing the values of no1 and no2 and reload the page. The page will update with the new result.

Question: What happens if I don’t supply the query values?

Answer: Try it. Just load the http://localhost:8080/index.html URL and leave off the query.

Accessing a missing property of an object (in other words, trying to get the properties no1 and no2 from a query that does not contain them) will produce the JavaScript value Undefined. Any calculations involving the value Undefined will produce the result Not a number, which when converted to a string, is displayed as NaN.

Question: Can I call the addition service by using fetch in a JavaScript program running in a web page?

Answer: That is a fantastic question, and the answer is yes. This is how most web pages work. We’ve already written an application that used fetch to get information from the weather server. We could write another application that used fetch to call the addition service to perform a calculation.

Click here to view code image

var url = "http://localhost:8080/docalc.html?no1=2&no2=3";

The JavaScript statement above creates a URL that could be used to call an addition service at docalc.html.

Click here to view code image

fetch(url).then(response => {
    response.text().then(result => {
        let resultParagraph = document.getElementById('resultParagraph');
        resultParagraph.innerText = "Result: " + result;
    }).catch(error => alert("Bad text: " + error)); // text error handler
}).catch(error => alert("Bad fetch: " + error)); // fetch error handler

This is the JavaScript that performs the fetch to get the result from the service. The service responds with text that is used to set the value of the resultParagraph element on the web page. This code is very similar to the code that was used to read the weather from openweather.org.

You can find this example code at Ch11 Creating Applications\Ch11-16 Addition Application. Stop the present server running and navigate to the file additionApplication.js in this folder. Use Visual Studio Code to run this program using Node.js and then navigate to http://localhost:8080/index.html in your browser. Click the “Add 2 + 3” button. This will run the fetch above, which will then be displayed on the page.

The Ch11-16 additional application browser screen is presented. The title, web service client demo is displayed in large and bold font at the top. The statement, uses a server to add two numbers together is displayed below the title. The button, add 2 and 3 is shown below this statement. The result: 5 is displayed at the bottom.

This is a big moment. Almost all this book has been leading up to this point. You now know how web applications work. The HTML document describes the page, and the JavaScript in the page can do things. If the JavaScript wants to get data from a server, it creates a request and sends it to the server, which decodes the request, generates the result, and sends it back. You should spend some time taking a long hard look at the web page, the server, and the client code until you understand what each part does.

Node package manager

You could use the modules from Node.js to create a complete application server. However, you would have to write a lot of code to decode the requests and build the responses. The good news is that someone has already built a system for creating servers. The system is called Express, and it provides what is called scaffolding, which you can use to construct an application that is powered by HTML pages and web services.

The even better news is that there is also a way of using prebuilt code like Express. It is called node package manager or npm. The npm program is provided with the Node.js installation. You use the npm program to fetch and install prebuilt modules that you can then add into your server programs using the require function that we have seen before. Each application has a configuration file called a manifest that identifies the packages that are to be used by the application. This is all especially useful and extremely powerful, but it is all built on the foundations that you have learned in this chapter. You will create arrow functions that give the behaviors of your server, and you will use promises to ensure that none of your functions block the execution of your program. You can find out how to build your first Express application at http://expressjs.com/en/starter/hello-world.html.

Deploying a Node.js server

The Node.js services that we have created so far have run on our local computer. You would not normally make your computer visible to the Internet so that other people can use your services. Instead, you would host your JavaScript program on an external server. You don’t need to own a server machine. Instead, you can run your JavaScript application as a service in the cloud. You can get started with this for free by creating an Azure account and then using the App Service Extension for Visual Studio Code to configure and deploy the service that you have created. You can find out more at https://azure.microsoft.com/en-us/develop/nodejs/.

What you have learned

In this chapter, you learned how JavaScript code can be embedded directly in a program as anonymous functions and how the arrow notation makes this easier. You also discovered how programs can interact with the network and how the JavaScript promise mechanism allows the applications to contain asynchronous execution. Finally, you have investigated the Node.js platform that allows JavaScript programs to run on a computer and provide services for JavaScript client applications running in a browser.

JavaScript arrays provide a sort behavior that will sort their content. We used this to sort the Fashion Shop stock list in order of stock level. The order of a sort is determined by a comparison function that is supplied to the sort behavior. The comparison function accepts two parameters, which are array elements. It compares the elements in some way and returns a value that is negative, zero, or positive, depending on the order in which they are to be sorted. The comparison function can be supplied as a named function or as an anonymous function directly as an argument.

An anonymous function can be expressed using an arrow notation in which the parameter list and body of the function are separated by an arrow operator (=>). If the body of the arrow function is a single statement, it does not need to be enclosed in a block, and if the single statement returns a value, the return keyword can be omitted.

JavaScript arrays provide a filter behavior. We used filter to create a list of Fashion Shop stock items with zero stock. The filter behavior returns another array containing selected elements. The behavior of the filter is determined by a filter function that is supplied to the filter behavior. The filter function accepts a single parameter and returns true if the value of that parameter means that it should be included in the filtered results.

JavaScript arrays provide a reduce behavior, which can convert an array into a single value. We used reduce to calculate the total value of all the stock in the Fashion Shop. The reduce behavior is provided with a function that accepts two parameters: the current total and a reference to an element in the array. The function calculates the new total by adding the value for the given element (in our case, the price of the element multiplied by the number in stock) to the total. The reduce behavior on an array is also provided with a starting value (which is usually 0) for the total.

JavaScript arrays provide a map behavior that applies a given function to every element in the array. We used this to apply a sale discount to the price of every item for sale in the Fashion Shop. The map behavior is provided with a function that accepts a single parameter—the element to be updated.

A JavaScript application running inside a web browser can consume the contents of a web service that is located at a particular address on the Internet. The web service can provide the data in the form of a JSON object, which can be decoded by the client application and displayed to the user. We used this create an application that read weather information from a server at openweather.org.

Some JavaScript operations, such as the fetch function that reads a message from a network, can take a noticeable time to complete. It is important that time-consuming operations such as fetch do not cause an active application to pause in a noticeable way. If a button-click handler in a web page takes a long time to complete, the web page would appear to have “locked up,” and the user would not be able to interact with it. JavaScript allows long-running operations (such as fetching from a network) to be performed asynchronously.

The JavaScript promise mechanism allows a programmer to invoke operations that will be performed asynchronously. A promise exposes a then property that can be used to specify JavaScript code that will be performed when the asynchronous behavior “promised” to the calling application has completed. A promise also exposes a catch property that specifies code to be performed if the asynchronous operation fails.

JavaScript promise operations can be chained together. This allows an action that processes data delivered by a promise to return a promise to produce the processed data. We used this to allow an asynchronous JSON decoder to run directly after a fetch operation has completed.

A JavaScript promise exposes a finally property that can be used to specify code that will be run whether the promise is “kept” (the operation completed successfully) or “broken” (the operation could not be completed). We used the finally property to run code that enabled a button in the HTML document.

The Node.js framework allows a computer to run JavaScript programs without opening HTML files in the browser. The Node application contains a JavaScript runtime environment that will run JavaScript code. Code running inside Node.js cannot interact with the user via an HTML document (because there is no document), but it can provide JavaScript powered services for other applications. Node.js can be downloaded and installed for free on most computing platforms. (It is an open-source application.)

You can run Node (the program that implements the Node.js framework) from the command line. Node can provide a console like that in the browser Developer View, or it can open files containing JavaScript code and run them. You can run Node from the command prompt within Visual Studio Code.

The Node.js framework is supplied with a number of modules. The require function is used in an application to load a module and make it available for use in a program. One such module is the http module, which can be used to create web servers and clients.

The http module in Node.js can be used to create a server. The server will run on a computer and accept HyperText Transport Protocol (HTTP)–formatted messages that will request services from that computer. Clients making requests of the server will use a uniform resource locator (URL) to specify the network address of the server, the port number (if the port is not port 80), and the path to the resource on the server. The local server that we used for the demonstration code has this address: http://localhost:8080/index.html.

The http.createServer method used to create a server is called with a single argument, which is the service function for that server. The service function takes two parameters: the request and the response. The request parameter contains a description of the request received from the browser, and the response parameter is an object that can be used to build the response.

The http.listen method is called with a parameter of the port number that the sever is to listen on. The listen method will call the service function each time a remote client makes a request of the server. The listen method will never stop running; it will repeatedly respond to requests. Our first server ignored the content of the request parameter and sent a simple text response. This response was sent each time a browser client navigated to the server.

A response contains a status code (which is 200 for success), a header (which is content type information), and the response text (which is the data that the server is sending to the client).

The service function can parse the request and obtain the path component of the URL that was specified by the client. The service function can then serve up different responses for different paths.

A URL can also contain query data which is made up of name-value pairs which can be used by the server function to determine the response that is to be provided. We created an addition server that used a query data string containing values for two numbers to be added together. Query data is one way that a client can communicate with a server.

A JavaScript program running inside a browser can use the fetch function to interact via query data with services provided by a server.

A single Node.js application can both serve up HTML pages for a browser and respond to queries. This is the basis by which many web applications work.

The Node package manager provides a way for prewritten JavaScript frameworks to be incorporated into applications. The Express framework provides the “scaffolding” that can be used to create JavaScript-powered applications that run from a server.

Here are some questions that you might like to ponder about what we have learned in this chapter:

What is an anonymous function?

An anonymous function is one that has no name. That’s probably not a useful answer, though. If you want to call a function by name, you can create it with a name. If you just want some code to give to another part of your application, you can just pass the code itself over. The sort method for an array needs to be given a behavior that tells it how to put items in order. We could pass the sort method the name of a function to call. Alternatively, we can provide the code itself in the form of an anonymous function.

Can I reuse code in an anonymous function?

No. Code in an anonymous function exists in one place in the code and is used from there. If you want to use a behavior in different parts of your program, you can make a named function and then call it by name every time you want to use it in your code.

Are there any performance advantages to using anonymous functions?

No. All that happens is that the JavaScript system places the code that implements the function in particular place in memory and then uses that address to call it. An anonymous function is called in exactly the same way as any other when the program actually runs.

Are there any performance advantages to using arrow functions to denote anonymous functions?

No. The arrow function was created to make it easier for programmers, not to make the program itself run more quickly.

Is there such a thing as an anonymous method?

No. A method will always have a name because it is named element in an object.

What does it mean if a function returns a promise?

A promise is an object that represents a statement of intent. At some point in the future, the code that implements the promise will run and either work (the promise is fulfilled, and the function specified by then is called) or fail (the promise is broken, and the function specified by catch is called). The code to implement the promise will run asynchronously, allowing the code that requested the action to continue running.

Can a promise have multiple then behaviors?

Yes, it can. You use the then method to tell a promise what to do when the promise is fulfilled. You can call then multiple times on a given promise. Each call of then can specify code to run when the promise is fulfilled. When the promise is fulfilled, the then functions will be called in the order that they were assigned.

Can multiple promises be active at one time?

Yes, they can. As an example, a program might fire off several successive calls to fetch to obtain multiple resources from the network. Note that because each call is asynchronous, the program has no idea which of the promises will be fulfilled first. It might be that the most-recent fetch returns its result first. It is the job of the program that requested the promises to synchronize the responses.

What happens if a promise is never kept?

If a promise is never kept, the then, catch, and finally functions will never be called by the promise.

What is the difference between a request and a response in a web server implementation using HTTP?

The request describes what is being asked for by the browser. It is a lump of data that describes the HTTP request. The request contains the URL entered so that the server can determine the path to the resource to be returned. The URL may also contain query items. The response object is used to build the response from the server. The response contains the status code for the response (200 means “worked okay”), header information, and the data to be sent back. The job of the server function is to use the request information to work out what is required and then put that information into a response to be sent back to the client.

How many query items can a URL contain?

A URL can contain many query items and each item can be quite long. If you look at the URL in the browser of an e-commerce site such as Amazon, you will see that the address can contain many query items. These are used by the server to maintain a session with the browser connection.

Can a Node.js application display graphics for the user?

Not directly. The Node.js platform will run JavaScript applications, but it does not maintain an HTML document for the application to communicate with the user. However, a web application running on a machine can be sent HTML documents by an application running under Node.js. The final example application, Ch11 Creating Applications\Ch11-16 Addition Application, does this.

Can an HTML server application create a “session” with a web client?

HTTP is described as stateless. Each request made by a web client is “atomic.” Once it has completed, the server forgets about it. If you want to create a “session” with a server, the application must provide data to the server program to identify the session it is part of. One way to do this is for code in the browser to use query string values to identify the session.

12
Creating games

What you will learn

Writing games is great fun. Unlike applications created to solve a specific problem, games are not always tied to a formal specification and don’t need to do anything useful. They only need to be fun to play. Games are a great place to experiment with your software. You can write code just to see what happens when it runs and see whether the result is interesting. Everyone should write at least one computer game in their lives. In this chapter, you’ll start creating games. You’ll learn how to make a complete game and finish with a framework you can use to create more games of your own design. Along the way you’ll discover how to use the HTML Canvas and learn more about the asynchronous loading of resources.

Use the HTML Canvas

Draw on a canvas

Make some of your own art

Animate images

Move an image

Control gameplay

Create game objects

Complete the game

Build your own game

What you have learned

Use the HTML Canvas

In this section, we’ll get started with the HTML canvas element. We’ll create some shapes and display them. Up until now the browser has determined the final position of every element on the screen. We have used Hyper Text Markup Language (HTML) and Cascading Style Sheets (CSS) to express preferences about layout, style, and color, but these are only general instructions. This is as it should be. It makes it possible for a page designer to create content without having to worry about the specifics of the output device. However, some displays must be drawn with pixel-level precision. The HTML Canvas is provided to allow programs to do this. The canvas is an area of the display, within which a program can precisely draw items.

Click here to view code image

<canvas id="canvas" width="800" height="600">
  This browser does not support a canvas.
</canvas>

The HTML above shows how we create a canvas element in an HTML document. It works in the same way as the audio element that we saw in Chapter 2 in the “Adding sound to the egg timer” section. In the same way that not all browsers can support audio, not all browsers can support the canvas element. If the canvas element is not supported (meaning the browser does not know what to do when it sees the word canvas) the HTML enclosed in the element is displayed. However, if the browser understands the word canvas it will ignore the text in the element so that the message does not appear. All modern browsers provide canvas support, but it is still important to make sure that your pages do sensible things when running on ones that don’t.

MAKE SOMETHING HAPPEN

Draw on a canvas

The best way to understand how a canvas works is to draw something on it. Open the browser and go to the Ch12 Creating Games\Ch12-01 Empty Canvas example page. An empty canvas is displayed as a white area on the screen underneath the heading. Press F12 to open the Developer View of the web page and select the Console tab so that we can enter some JavaScript statements and draw on the canvas.

The initial color of a canvas is white, so the canvas in the figure above just looks like an empty area of the page. Now we need to write some JavaScript to draw items on the canvas. We know that JavaScript programs interact with an HTML document by obtaining a reference to an element in the document and then interacting with that element. The first thing we need to do is get a reference to the canvas element by using the document.getElementById method. Enter the statement below and press Enter.

Click here to view code image

> var myCanvas = document.getElementById("canvas");

When you press Enter, a variable called myCanvas is created and made to refer to the canvas element. This process does not return a value, so the JavaScript console displays undefined.

Click here to view code image

> var myCanvas = document.getElementById("canvas");
<- undefined

You might think that we could now call methods on the myCanvas reference to draw things on the canvas in the HTML document. However, this is not how it works. A canvas provides a drawing context that is used to perform drawing operations. We want to use the 2D drawing context, so we have to ask the canvas for it. Enter the statement below and press Enter:

Click here to view code image

> var myContext = myCanvas.getContext('2d');

When you press Enter, a variable called myContext is created that refers to the 2D graphics context of the canvas. This process does not return a value, so the JavaScript console displays undefined.

Click here to view code image

> var myContext = myCanvas.getContext('2d');
<- undefined

The context object can be used for all further graphics operations. It exposes many methods for drawing on the canvas. One way to draw is to define a path and then ask the context to draw the path. Enter the following statement to begin a path:

> myContext.beginPath();

A path contains move and draw operations. You can add many of these operations to the path. We are going to start the path by moving to the origin. The moveTo method accepts two parameters. The first is the “x coordinate” or distance across the screen of a pixel position. The second parameter is the “y coordinate” or distance down the screen. The position (0,0) is known as the origin of the graphics coordinates. Let’s move the path position to the origin. Enter the following statement to move the path position to (0,0).

> myContext.moveTo(0,0)

Moving doesn’t draw anything on the canvas. To draw a line, we use the lineTo method, which also accepts x and y coordinates as parameters. Enter the following statement to draw a line to the position (800,600).

> myContext.lineTo(800,600);

We have told JavaScript to draw a line, but the line has not appeared on the screen yet. This is because the context saves all the move and draw operations until the stroke method is called. Enter the following statement to draw the line on the canvas:

> myContext.stroke();

The browser screen displays a page with the title of the empty canvas. The options such as elements and console are displayed on the top right. Below these options, the filter option is displayed. Few lines of code are displayed in the right pane under the console. The left pane is struck through by a diagonal line.

When you enter the stroke method, you should see a diagonal line drawn down the entire canvas. This is because the canvas has been defined as being 800 pixels wide and 600 pixels high.

Canvas coordinates

You might have been surprised by the line that has just been drawn. You might have expected the line to start at the bottom-left corner, rather than the top. This is because placing the origin in the top-left corner is standard practice when drawing graphics on a computer. The important thing to remember is that the origin, which is the point with the coordinate (0,0), is the top-left corner of the display. Increasing the value of x moves you toward the right of the screen, and increasing the value of y will move you down the screen, as shown in Figure 12-1. If you draw outside the range of the canvas dimensions—for example, if we tried to draw something at location (1000,1000)—this would not be displayed, but it would not cause an error in the program. I’ve chosen a canvas size of 800 pixels wide and 600 pixels high because this results in a reasonable game display on most devices.

Figure 12-1 Canvas coordinates

Computer art

We can use JavaScript graphics to create some nice-looking images. The program below draws 100 colored lines and 100 colored dots. The program uses functions that create random colors and positions on the display area.

The JavaScript code to display graphics is presented. The title tag is Ch12-02 Art Maker. The line, body on load equals "doDrawArt()" calls the doDrawArt function when the page is loaded. The line, canvas id equals "canvas" width equals "800" height equals "600" sets the canvas width to 800 wide and 600 high.

The JavaScript code to display graphics is presented. The line, var canvasWidth equals 800 is a global variable giving canvas width. The line, var canvasHeight equals 600 is a global variable giving canvas height. The var context is the canvas drawing context. The function getRandomInt(min, max) gets a random integer in the specified range. The line colors equals left bracket (list of various colors) right bracket lists the color names. The function getRandomColor picks a random color name from the list. The function drawDot(x, y, radius, style) draw a dot of a particular size and style. The line inside the function drawDot, context.arc(x, y, radius, 0, 2 Math.PI) draws a circle. The line inside the function drawDot, context.fillStyle equals style sets the fill style to the color. The line inside the function drawDot, context.fill fills in the dot. The function drawRandomDot draws a random dot. The lines of code inside the function drawRandomDot picks a random dot radius, pick random x, pick random y, pick random color, and draw the dot. The function drawLine(startX, startY, endX, endY, style, linewidth) draws a line. The codes inside this function is written to start the path, move to the start of the line, draw the line, set the line style, set the line thickness, and draw the line. The function drawRandomLine draws a random line. The line of code, var startX equals getRandomInt (0, canvasWidth) picks line start x.

The JavaScript code to display graphics is presented. The lines of code inside the function drawRandomLIne that calls the function getRandomInt are to pick line start y, pick line end x, pick line end y, pick random line color, pick random line thickness, and draw a random line. The function doDrawArt includes the code to get the drawing canvas, set the draw canvas to 2 d, repeat 100 times, draw a random dot, and draw a random line.

The computer art program can produce some rather nice-looking images, as you can see in Figure 12-2. You can find it in the example Ch12 Creating Games\Ch12-02 Art Maker folder. Each time you run the program, it will generate a different image because the positions of each item are determined randomly.

Figure 12-2 Computer art

CODE ANALYSIS

Random artwork

As you can see in Figure 12-2, the program above can produce some vaguely artistic-looking images. However, you may have some questions about the code.

Question: Where do the context, canvasWidth, and canvasHeight values come from?

Answer: These variables are global. They are not declared in any function, so they can be shared by all of them. I’ve decided that it makes the program easier to write if these values are shared by all the functions in the program. The value of context (the context to be used for all the drawing operations) is set at the start of the doDrawArt function.

Question: How does the program draw a round dot?

Answer: There is no way of drawing a round dot on an HTML canvas. Instead, the program draws a circle and fills it in. The arc drawing method accepts a coordinate that gives the center of the arc, a radius, and two angles in radians. It then draws an arc between the two angles. If the initial angle is 0 and the second is 2*Pi (which is the radian equivalent of 360 degrees), the result is a circle.

Click here to view code image

context.arc(x, y, radius, 0, 2 * Math.PI);

You can use this method to draw interesting curves by only drawing part of the circle. This will also provide a very good workout of your trigonometry skills.

Question: Why does the program subtract the radius value from the random dot positions?

Click here to view code image

var radius = getRandomInt(5, 100);
var x = getRandomInt(radius, canvasWidth-radius);
var y = getRandomInt(radius, canvasHeight-radius);

Answer: Above, you can see the statements that pick a random position to draw a round dot. The radius of a dot is between the values 5 and 100. When the dot is drawn, I don’t want it to “go off” the picture. This is an artistic decision—JavaScript will happily draw items that don’t all fit on the screen. The getRandomInt function picks a random number between start and end values. By making sure that the start position is never less than the radius of the dot or greater than the canvas size subtracted from the radius, I can make sure that my dots never go off the screen. If your artistic judgment is different from mine, you are welcome to change this code.

Question: Does the drawing have to be on a white background?

Answer: No. A program can use the fillRect drawing function to draw a filled rectangle to change the canvas to any desired color:

Click here to view code image

context.fillStyle = "blue";
context.fillRect(0, 0, canvasWidth, canvasHeight);

The statements above would fil the entire canvas with blue.

Question: Can I create my own colors?

Answer: Yes. The art program above uses fixed color names such as “red,” but you can also create a color by calling the rgb function with three arguments giving the intensities of red, blue, and green in the color:

rgb(255,0,0)

The intensity values can range from 0 to 255. The above call of rgb would produce the value bright red.

Click here to view code image

function getRandomColor() {
  var r = getRandomInt(0,255);
  var g = getRandomInt(0,255);
  var b = getRandomInt(0,255);
  return "rgb("+r+","+g+","+b+")";
}

This version of getRandomColor produces a completely random color by choosing random values for red, green, and blue and then creating an rgb result that makes that color. You can find it in the Ch12 Creating Games\Ch12-03 Random Color Art Maker example folder. You might like to compare the results of the two programs to see which you prefer.

MAKE SOMETHING HAPPEN

Make some of your own art

You can have a lot of fun with the art program above to make some really interesting images. Here are a few ideas that you might like to explore:

You could create a program that displays a different pattern every now and then.

You could use the time of day and the current weather conditions to determine what colors to use in the pattern and create a display that changes throughout the day (perhaps with bright primary colors in the morning and mellower and darker colors in the evening).

If the weather is warm, the colors could have a red tinge, and if it’s colder, you could create colors with more blues.

Draw images on a canvas

In Chapter 2, in the “Add images to web pages” section, we saw that an HTML document can use img elements to display images. The images were stored in files on the server alongside the HTML documents. The browser loads the image files and displays them. We are going to use images for the objects in our game. Our game must load the images and can then draw them on the canvas.

Image file types

There are several different formats for storing pictures on computers. There are two popular formats that you might want to use:

PNG—The PNG format is lossless, meaning it always stores an exact version of the image. PNG files can also have transparent regions, which is important when you want to draw one image on top of another. Files containing PNG images have a .png file name extension.

JPEG—The JPEG format is lossy, meaning the image is compressed in a way that makes it much smaller but at the expense of precise detail. Files containing JPEG images have the file name extension .jpg or .jpeg. I tend to use the shorter extension (.jpg) to name my JPEG files, but you can use either. Just make sure that the name of the file matches the reference in the web page.

The games you create should use JPEG images for the large backgrounds and PNG images for smaller objects drawn on top of them. If you have no usable pictures of your own, you can use the ones I’ve provided with the sample files for this chapter, but your games will work best if you use your own pictures.

If you need to convert images into the PNG format, you can load an image using the Microsoft Paint program and then save it in this format. With Paint, you can also scale and crop images if you want to reduce the number of pixels in the image. Mac owners can use the Preview image editor, and if you are using a Unix-powered PC, you can use the Gimp program, which is freely available for most machines. You can download Gimp here: https://www.gimp.org.

Figure 12-3 shows my picture of the cheese we’ll be using in the game that we will create. In the game, the player will control the cheese and use it to catch crackers around the screen. You can use another picture if you wish. In fact, I strongly advise that you do.

Figure 12-3 Cheese

Load and draw an image

The JavaScript to create and draw an image looks very easy to write:

The JavaScript code for drawing an image is presented. The line, var image equals new Image() creates a new image object. The line, image.src equals "cheese.png" sets the src property to the location of the image. The line, context.drawImage(image, 0, 0) draws the image on the screen.

The statements above are all completely correct. They create a new Image, tell the image that the path to the image resource is the URL cheese.png, and then draw the image on the canvas context at the top-left corner of the screen (coordinate 0,0). Unfortunately, these statements will not work. This is because loading images is like fetching everything else from the network. It takes a while to complete. The image starts to load when the src attribute is set, but the JavaScript code above draws the image before it has loaded. This means that the cheese would not be displayed. Loading an image is performed asynchronously. We first saw asynchronous operation in Chapter 11 in the “Fetch data from a server” section. In that section, we used the fetch function to get weather data from a server.

We can get a notification that an image has been loaded by connecting a function to the onload property exposed by the image. When the image has been fetched, it calls this function. This is called an event, and the function connected to the event is called an event handler. Connecting an event handler to an event is called binding the handler to the event. We could bind an event handler function that draws the image as soon as it has arrived:

Click here to view code image

var image = new Image();
image.src = "cheese.png";
image.onload = () => context.drawImage(image, 0, 0) ;

These statements would draw the cheese as soon as it was loaded. The last statement binds an arrow function to the onload event so that the image is drawn when it has been loaded. You can find a program that draws cheese in this way in the Ch12 Creating Games\Ch12-04 Image Load Event folder in the example programs. We can also bind an event handler to the onerror event that an image will generate if the image cannot be loaded.

Click here to view code image

image.onerror = () => alert("image not loaded");

This statement binds an arrow function to the onerror event. The arrow function displays an image not loaded alert. You can find a program that produces this error alert in the Ch12 Creating Games\ Ch12-05 Image Load Fail example programs folder.

Create an image loading promise

A JavaScript program can use an event to detect when a single image is loaded, but our game will need to load several images for the different elements in the game. We need to draw cheese, crackers, tomatoes, and a tablecloth background. It would be hard work to bind event handlers to all the onload events for all these images in turn. However, it turns out that JavaScript has a very neat way of managing multiple asynchronous operations that is based around the JavaScript Promise object.

When we used the fetch function in Chapter 11 in the “Fetch data from a server” section, we discovered that the fetch function returns a Promise object. Our program bound handlers to the then and catch events exposed by a Promise. The first thing we need to do is create a function that generates a Promise for the image loading process.

The JavaScript code for the function getImageLoadPromise is presented. The function has a parameter url. The line, return new Promise((kept, broken) implies left brace represents the controller function for the promise. The line, var image equals new Image() creates the new Image. The line, image.src equals url sets the url of the image. The line, image.onload equals () implies kept (image) connects the onload event to the kept parameter. The line, image.onerror equals () implies broken(new Error('could notload\ plus url)) connects the onerror event to the broken parameter.

The getImageLoadPromise function is given the URL of the image resource and returns an Image object containing that resource. The constructor for a new Promise object is given a function that accepts two parameters. This is the controller function for the promise. The controller function above is an arrow function that accepts two parameters that specify event handlers to be called when the promise has been kept (the image was loaded) or broken (the image could not be loaded). The controller function creates the new image, sets the src property to the url, and then connects the onload event in the new image to the kept function in the promise and the onerror event in the new image to the broken function in the promise. You might need to take some time getting your head around this, so it might be helpful if we look at how a Promise is used:

The JavaScript code for the usage of promise is displayed. The line, var imagePromise equals getImageLoadPromise("images/cheese.png") gets the promise. The line, imagePromise.then((image) implies context.drawImage(image, 0, 0)) binds to then. The line, imagePromise.catch ((Error) implies alert(error)) binds to catch.

This code uses getImagePromise to get a promise and then uses the then part to trigger drawing the image and the catch part to trigger displaying an alert. You can find a program that uses this promise in the Ch12 Creating Games\Ch12-06 Promise Image Load in the example programs folder.

Use Promise.all to handle multiple promises

Now that we can create promises to handle image loading, we can use a very powerful JavaScript feature called Promise.all to manage image loading. Promise.all lets a program wait for a number of promises to complete. All our program has to do is assemble a list of promises and give them to a call of Promise.all. The Promise.all method delivers a single promise that is fulfilled when all the promises have been fulfilled.

The JavaScript code to make an empty promise list is presented. The for loop, for (url of imageUrls) inside the function getImages(imageUrls) work through the list of image URLs. The line, promiseList[promiseList.length] equals getImageLoadPromsie(url) creates a load promise and add it to the list. The line, Promise.all(promiseList).then((images) works through the images returned by the promises. The lines of code inside the promiseList function includes the code to set x draw coordinate to 0, set y draw coordinate to 0, work through the images returned by the promises, draw the image, move x across by the width of the image, and move y down by the height of the image.

The getImages function creates a list of promises by calling the getImageLoadPromise function for each of the image URLs it has been asked to load. It then calls Promise.all and passes it this list. When all the promises in the list have been fulfilled, the then part of Promise.all is called, which works through the images that were returned and draws them down the canvas. The getImages function is called with a list of image paths:

Click here to view code image

var imageNames = ["cheese.png", "tomato.png", "cracker.png", "background.png"];
getImages(imageNames);

Figure 12-4 shows the result produced for each of the images in the game that have been loaded from the image files.

Figure 12-4 Game images that have been loaded and displayed

Use async to “wait” for promise results

The getImages function that we have created draws the images on the screen when they have all been loaded. However, the game program will not want to do this. Once the images are ready, the game application will want to start running and display the images as the game runs. Ideally, we would just like the program to be able to “wait” for the result from a call of the getImages method.

It turns out that there is a way of doing this, but it doesn’t involve waiting. Instead, it involves await. To understand how await works, we must first go back to why we are doing all this. The problem we are solving is in two parts:

Some things (for example fetching images) take a while to perform.

Our programs are not allowed to stand and wait for things to be performed.

JavaScript solves this problem by letting us create a Promise object that describes the intent of the action. We attach code to the then part of the Promise, which will run when the promise is kept. Setting up a promise doesn’t take very long so our program does not spend time waiting. But using then is a bit clumsy in this situation. We don’t want to do something when the images have arrived; we just want to move on to the next part of the game.

JavaScript provides a way of “wrapping” up a Promise, which makes things easier. It uses the keywords async and await. Firstly, any function that contains an await must be marked as async. This tells JavaScript to change the way that the function is called to make the await possible. Then the function can use the await keyword to wait for the results of promises. We could make an asynchronous version of getImages as follows:

The screenshot shows the program source code with async function. The line, async function getImages(imageUrls){ represents the asynchronous function to get all the images. The line, var promiseList equals []; empty the list of promises. The line, for (url of imageUrls){ works through the image URLs. The line, promiseList[promiseList.length]equals getImageLoadPromise(url); Get an image load promise for each URL and add it to the list. The line, var result equals await Promise.all(promiseList); is represented to wait for all the promises to be fulfilled. The line, return result; is represented to return the list of images.

I’ve highlighted the await and async keywords in the listing above. When a program reaches a statement that awaits a promise, the JavaScript execution of the function containing the statement is suspended until the promise is fulfilled. The getImages function now awaits the result of the call of the Promise.all function. When the promise is fulfilled, the function is resumed.

We don’t need to know how this magic works, we just have to marvel at how much easier it makes it for a program to wait for asynchronous actions to complete. The only hard thing to remember about this is that calls of async functions must always be made using await. In other words, any calls to this version of getImages must await it. This is the complete code of the method that draws the images using await:

The source code is displayed with await.The line, async function doLoadImage() { is called when the HTML document is loaded. The line, var canvas equals document.getElementById("canvas"); gets the canvas from the document. The line, if (canvas.getContext) { check for a graphics context. The line, context equals canvas.getContext('2d'); get the "2d" graphics context. The line, var imageNames = ["cheese.png", "tomato.png", "cracker.png", "background.png"]; represents the image name array. The line, var images equals await getImages(imageNames); gets the images. The line, var x equals 0; work through the images and display them.

CODE ANALYSIS

Promise.all and async/await

You can find the async/await version of the image loading program in the Ch12 Creating Games\Ch12-08 Promise Await Load in the example files folder. It displays the images just like the earlier versions. However, the code to fetch and use the images is much simpler because it looks like sequential code. You may have some questions about all this:

Question: How does the Promise object work?

Answer: I don’t know the details. I know that an operating system (Windows 10, macOS, or Linux) can be used to control the starting and stopping of different parts of active programs called threads. Also, I know that different parts of the JavaScript environment run on different threads that are managed by the browser, but beyond that, I don’t know how they are run. I just know how to use promises, which is good enough for me. After all, I don’t really know how the engine in my car works, but I’m very happy to drive it.

Question: What happens if one of the promises in a Promise.all fails?

Answer: Promise.all is given a list of promises. If one of these can’t be kept (perhaps an image resource can’t be found), the catch behavior will be called. I’ve left this out of my example above to keep things smaller. The catch behavior is given the error message from the first promise that failed.

Question: Could a program await the result of the fetch function we used in Chapter 11 to fetch network data?

Answer: Yes, it could, and in some situations, it makes using fetch much easier.

Question: Does using await cause the browser user interface to lock up?

Answer: Good question. We use Promise and await to prevent functions in our program taking a long time to complete and causing the browser user interface to lock up. When a JavaScript function runs in response to a button click on an HTML page, the browser will not accept any further user input until the function finishes. Using a Promise will make a function complete quickly because it does not have to wait for the promise to be fulfilled; it just has to start the promise. You might think that if you use await in a function that function is stopped until the Promise is fulfilled. However, this is not what happens. Instead, JavaScript converts the code following the async into the body of a “then” event handler, creates a Promise, and then runs it. Both Promise and await work in the same way.

Question: What happens if an awaited Promise cannot be fulfilled.

Answer: We can add a catch element to a Promise to nominate JavaScript to run if the Promise cannot be fulfilled. A program can catch errors in awaited promises by enclosing the await in a try-catch construction.

PROGRAMMER’S POINT

Invest some time in understanding Promise and await

The effort of understanding Promise and await will make your head hurt. At least it did mine. But it is worth it. It lets you create applications that can load huge chunks of data and spend ages processing it without having users complain that their user interface gets stuck. It also lets you understand the code in frameworks that you will want to use, many of which use asynchronous behaviors. If you are finding it difficult to understand what they do, keep going back to the two problems that they were created to solve.

Animate images

The drawImage function is given x and y values that specify where the image is to be drawn.

context.drawImage(cheese,x,y);

The statement above would draw the Image referred to by cheese on the canvas. The values in the variables x and y specify where in the canvas the image above would be drawn. We can make an image appear to move by repeatedly drawing the image at slightly different positions. This is how all games work. To perform the game animation, we need a regular source of update events. In Chapter 3 in the “Create a ticking clock” section, we used the setInterval function to repeatedly call a function at regular intervals and make our clock tick. We could use this to trigger game display updates, but this would not be a very good idea because it would result in the game display flickering.

If the browser redraws the screen while our game is halfway through updating the positions of objects on the screen, the player would see the display appear to flicker. To avoid flickering, we need to synchronize the game updates with screen updates from the browser. Fortunately, there is a way to do this. The browser maintains a window object, which contains methods that we can use in our applications. One of these is the requestAnimationFrame method. This method accepts a single parameter, which specifies a function to call the next time the browser is updating the display.

Click here to view code image

window.requestAnimationFrame(gameUpdate);

The statement above asks the browser to call the gameUpdate method the next time the browser is updating the display. The game can then redraw the canvas as part of this process.

"The source code is presented to draw the cheese image using gameUpdate method. The line, context.fillStyle equals ""cornflowerblue""; Set the fill color to cornflowerblue. The line, context.fillRect(0, 0, canvasWidth, canvasHeight); draws a blue rectangle that clears the canvas. The line, context.drawImage(cheese, x, y); draws the cheese on the canvas. The line, x equals x plus 1; updates the value of x. The line, y equals y plus 1; updates the value of y. The line, window.requestAnimationFrame(gameUpdate); requests the next call of the animation frame."

This is a gameUpdate function that will draw the cheese image moving down the screen. The screen is cleared before each redraw. After each draw, the values of the x and y positions of the cheese are increased by 1, which will move the cheese draw position.

MAKE SOMETHING HAPPEN

Move an image

We can investigate the way that games make objects appear to move by opening the example page in the Ch12 Creating Games\Ch12-09 Moving Cheese folder. If you open this page, you should find that the cheese moves majestically down the screen for a while and then disappears off the bottom.

Most browsers update the display 60 times a second. The screen is 600 pixels high, and the cheese is moved down the screen one pixel each time it is updated. This means that after around 10 seconds, the cheese will vanish off the bottom of the screen. If you want to make the cheese appear to move more quickly, you can increase the amount you add to the position. The amount you change the position of an item on the screen gives you the speed of that item. See if you can change the program to make the cheese move twice as fast down the screen. These are the two statements that you need to look for:

x = x + 1;
y = y + 1;

By changing the values to 2, you can double the speed. You can find my faster version in the Ch12 Creating Games\Ch12-10 Speedy Cheese example folder.

Control gameplay

Now that we know how to make things move around the screen, the next thing we need is a way that a player can control them. We are going to use the keyboard to steer the cheese with the arrow keys. When the user presses an arrow key, we want the cheese to move in the corresponding direction. To make this work, we are going to create an event listener that runs when the player presses a key on the keyboard.

Window events

We have already used the requestAnimationFrame function to ask the window object to tell our game when it is time to redraw the screen. Now we are going to ask the window object to bind a function to events generated by the keyboard. The addEventListener provided by the window object lets a program connect a JavaScript function to a particular event. The events are specified by name, and there are many events. We can start by investigating how events work. We are going to use the keydown event.

The screenshot displays the source code with window object. The line, var resultParagraph equals document.getElementById("result"); get a reference to the paragraph that will display key values. The line, window.addEventListener("keydown", (event) right arrow { listens for key down messages.

The screenshot displays the source code to add the arrow function to the keydown event. The statement, resultParagraph.innerText equals "Key Down: " plus event.code; display the code property of the event.

The function above adds an arrow function to the keydown event. The function is supplied with an event parameter. It displays the code attribute of the event in a paragraph in the document.

CODE ANALYSIS

Keyboard events

You can find the keyboard event handler code in the Ch12 Creating Games\Ch12-11 Keyboard Events example folder. Use the browser to open this page and investigate what it does.

The screenshot is displayed with the title that reads. "Keyboard Events" is displayed. The text tat reads "This example binds an event handler to the keyboard event. Each key that you press is displayed here. Key down: Key A."

Above, you can see the display that is produced when I pressed the A key on the keyboard. Try some other keys, including nonprinting ones such as Shift and Control. Also, try holding down the Shift key and pressing letters.

Question: Why does it not display the character produced by that key on the keyboard?

Answer: The code values that are captured by this event are more concerned with the actual key rather than the character that is sent to a program when a key is pressed. Each key has a name (the A key is called “KeyA”), including the Shift keys. This event even distinguishes between left and right Shift keys, calling them “ShiftLeft” and “ShiftRight.” This is very useful for our game.

Question: Can a program detect when a key is released?

Answer: Yes. A program can bind to an event called keyup, which is triggered when a key is released.

Question: Does this code detect all keypresses on the computer?

Answer: No. The key events only fire when the browser is the active application. If the user selects another application, the keyboard events will no longer happen.

Question: Can a single event have multiple listeners?

Answer: Yes. The window will call each of the functions bound to a particular event in turn.

Control object position with a keyboard

We can now use the keyboard to control the draw position of the cheese, making it possible for the player to steer the cheese around the screen:

The source code is displayed to bind the event listener to the keydown event and to use key values. The line, x equals x minus 1; decrease x to move to the left. The line, x equals x plus 1; increases x to move to the right. The line, y equals y minus 1; decrease y to move up. The line, y equals y plus 1; increase y to move down.

The code above binds an event listener to the keydown event and then uses key values to control the x and y positions of the cheese. When the cheese is drawn at its new position, it will appear to move under the control of the player.

CODE ANALYSIS

Cheese steering

You can find the cheese steering code in the Ch12 Creating Games\Ch12-12 Keypress Cheese Control example folder. Use the browser to open this page and investigate what it does.

You can press the arrow keys to move the cheese around the screen. Each time you press an arrow key, the cheese moves one pixel in that direction.

Question: How does the cheese appear to move?

Answer: Remember that the canvas is being redrawn 60 times a second. Keyboard events will happen in-between redraws and update the x and y positions of the cheese so that the cheese appears to move.

Question: Why does the value of y increase as the cheese moves down the screen?

Answer: This is because the origin of the coordinates (the point with the coordinate 0,0) is the top-left-corner. This means that increasing the value of y will move the cheese down the screen.

Question: What happens if I move the cheese off the screen.

Answer: Quick answer: You can’t see it anymore. Longer answer: You can think of the canvas as a view onto a larger area. If you move the drawing position out of the visible area, you will not be able to see the object, but you can make it visible again by moving it back into view.

Question: Why does the cheese start to move continuously if I hold down an arrow key?

Answer: This is because keys on the keyboard will auto-repeat if held down. This causes repeated calls to the event handler, causing the cheese to move continuously. This is not a very good way to get continuous movement. In the next section, we will discover a better way.

Question: How would I make the cheese move more quickly?

Answer: To increase the speed of the cheese, you can add or subtract a value greater than 1 from the position each time the key is pressed.

Use keydown and keyup events

The previous example showed the principle of controlling an object with a keyboard, but it was not very user friendly. We don’t want the user to have to press the key each time they want to move the cheese a small amount. It would be much better if the cheese would move while a key was held down and stop when the key was released. We can do this by detecting both keydown and keyup events and using them to control the speed of the cheese.

The source code shows the method to control speed and position. The line, var cheeseX equals 0; is marked for the cheese x position. The line, var cheeseY equals 0; is marked for the cheese Y position. The line, var cheeseSpeed equals 5; represents the overall speed of the cheese. The line, var cheeseXSpeed equals 0; represents the current X speed of the cheese. The line, var cheeseYSpeed equals 0; represents the current Y speed of the cheese.

These variables control the speed and position of the cheese in our game. The speed and position values are used in the function gameUpdate, which updates the cheese position and then draws it.

The screenshot displays the source code to control and update the positions of the cheese. The line, context.fillRect(0, 0, canvasWidth, canvasHeight); is represented to clear the canvas. The line, cheeseX equals cheeseX plus cheeseXSpeed; updates the X position. The line, cheeseY equals cheeseY plus cheeseYSpeed; updates the Y position. The line, context.drawImage(cheese, cheeseX, cheeseY); draws the cheese. The line, window.requestAnimationFrame(gameUpdate); connects to the next operation.

Each time this function is called, it will clear the screen, update the position of the cheese, and then draw the cheese at the new position. If the speed values are zero, the cheese will not move with each redraw.

Click here to view code image

window.addEventListener("keydown", (event) => {
    switch(event.code){
        case 'ArrowLeft':
            cheeseXSpeed = -cheeseSpeed;
            break;
        case 'ArrowRight':
            cheeseXSpeed = cheeseSpeed;
            break;
        case 'ArrowUp':
            cheeseYSpeed = -cheeseSpeed;
            break;
        case 'ArrowDown':
            cheeseYSpeed = cheeseSpeed;
            break;
    }
});

This event hander starts the cheese moving when the user presses a key. It doesn’t move the cheese on the screen; instead, it sets the speed value of the cheese so that it will move in the selected direction the next time the update method is called. If the cheese is to move backward or upward, the speed for that direction will be negative. Because the position of the cheese is being updated repeatedly by the gameUpdate function, this will mean that the cheese will start to move as soon as the key is pressed down.

Click here to view code image

window.addEventListener("keyup", (event) => {
    switch(event.code){
        case 'ArrowLeft':
            cheeseXSpeed=0;
            break;
        case 'ArrowRight':
            cheeseXSpeed=0;
            break;
        case 'ArrowUp':
            cheeseYSpeed=0;
            break;
        case 'ArrowDown':
            cheeseYSpeed=0;
            break;
    }
});

This is the event handler that causes the cheese to stop moving when the player releases a key. It sets the speed value for the particular direction to zero.

WHAT COULD GO WRONG

Losing focus

You can find this cheese steering code in the example program Ch12 Creating Games\Ch12-13 Steerable Cheese. If you open the page in this folder with a browser, you will find that you can control the cheese movement very well. If you hold down two arrows you can even make the cheese move diagonally. However, the code does have a problem. If you start the cheese moving and then select another window on your desktop the cheese doesn’t stop when you release the movement key. This is because a modern windowed operating system like Windows 10, macOS, or Linux has the idea of focus.

At any given instant, the events from the keyboard and mouse are sent to the currently selected window, which is called the one that has focus. As soon as you select another application, the browser moving our cheese around loses focus and keyboard events are no longer sent to it. This means that there is no keyup message to stop the cheese moving, which causes it to keep moving and eventually vanish off the canvas.

We can fix this by binding a handler to a window event that is fired when the application loses focus. This is called the blur event. When this event fires, the game must stop the movement of the cheese.

Click here to view code image

window.addEventListener("blur", (event) => {
    cheeseXSpeed = 0;
    cheeseYSpeed = 0;
});

The code above shows how we would do this. When the window loses focus, it now sets the speed values for the cheese to 0, causing it to stop moving. The application in the Ch12 Creating Games\Ch12-14 Steerable Cheese with focus example folder uses this event handler to stop the cheese moving when browser loses focus. If you repeat the experiment you performed with the earlier version, you will find that the cheese stops moving as soon as you select a different window from the browser.

Create game objects

The game we are making is called “Cracker Chase.” The player will control the cheese, with the aim of capturing as many crackers as possible while avoiding the deadly killer tomatoes. The game will display four different items on the screen:

The tablecloth background—This contains an image that is the background of the game.

Cheese—The player will steer the cheese around the screen trying to capture crackers and avoid the killer tomatoes.

Crackers—The player will try to capture crackers by touching them with the cheese.

Killer tomato—The tomatoes will chase the cheese. If a tomato catches the cheese, the game ends.

Game sprites

Each of these screen objects is called a sprite. A sprite has an image drawn on the screen, a position on the screen, and a set of behaviors. Each sprite will do the following things:

Initialize itself when the game is loaded.

Draw itself on the screen.

Update itself. Each sprite will have a characteristic behavior.

Reset itself between games. When we start a new game, we must reset the state of each sprite.

Sprites might have other behaviors, but these are the fundamental things that a sprite must do. We can put these behaviors into a class:

The source code is presented to shows the behavior of sprite. The line, constructor(game, url) { represents the sprite constructor. The line, this.game equals game; stores the game the sprite is part of. The line, this.url equals url; shows the path to the sprite image. The line, reset(){ is represented to rest the sprite for a new game. The line, getInitializePromise() { gets a promise to perform initialization. The line, this.reset(); resets the sprite when the image has loaded. The line, resolve(true); resolve the load promise.

CODE ANALYSIS

Sprite superclass

The code above defines the superclass for all the sprites in the game. You may have some questions about it.

Question: What is the game parameter used for in the initializer?

Answer: When the game creates a new sprite, it must tell the sprite which game it is part of because some sprites will need to use information stored in the game object. For example, if a cracker is “captured,” the score value in the game will need to be updated. The sprite constructor makes a copy of the game reference so that it can interact with the game when it needs to.

Programmers say that the sprite class and the game class will be tightly coupled. Changes to the code in the CrackerChaseGame class might affect the behavior of sprites in the game. If the programmer of the CrackerChaseGame class changes the name of the variable that stores the score from score to gameScore, the Update method in the Cracker class will fail when a cracker is captured.

I think about coupling in the same way I think about global variables. Global variables are an easy way to allow several functions to share application data. However, when I write the code, I have to make sure that none of my functions change the value of a global variable in a way that the other functions weren’t expecting. A mistake I make in one function might cause another to fail.

Coupling classes together makes it easier for them to cooperate, but it also means that changes to one class might break behaviors in the other class. When I decide to use global variables or couple two classes together, I’m always aware that I’m balancing convenience (easier and quicker to write) against risk (slightly more vulnerable to mistakes).

Question: Why is the update method empty?

Answer: You can think of the Sprite class as a template for subclasses. Some of the game elements will need methods to implement update and reset behaviors. The cheese sprite will need an update method that moves it around the screen. The cheese class will be a subclass of Sprite and add its own version of this method.

Question: How is the getInitializePromise method used?

Answer: The game will create a list that contains all the sprites in it. Once all the sprites have been created, the game will then create a list of initialise promises from the sprites that it will feed into a call of Promise.all. In other words, the promise behavior that we used to load individual images in the previous section has been moved into the Sprite class.

The Sprite class doesn’t do much, but it can be used to manage the background image for this game. The game will take place on a “tablecloth” background. We can think of this as a sprite that fills the screen. We can now make our first version of the game object that contains a game loop that just displays the background sprite.

The game object

The CrackerChaseGame object holds all the game data, including a list of all the sprites that the game will use. It also holds methods that will enable the gameplay.

"The screenshot displays the source code for the CrackerChaseGame. The line, gameUpdate(timeStamp) is the method to update the game. The line, for (let sprite of this.sprites) updates all the sprites. The line, for (let sprite of this.sprites) draws all the sprites. The line, window.requestAnimationFrame(this.gameUpdate.bind(this)); requests the next update. The line, gameReset() resets all the sprites. The line, this.canvas equals document.getElementById(""canvas""); gets a reference to the game canvas. The line, this.context equals canvas.getContext('2d'); gets the graphic context for this canvas. The line, this.canvasWidth equals canvas.width; stores the canvas width. The line, this.canvasHeight equals canvas.height; stores the canvas height. The line, this.sprites equals []; creates an empty sprite list. The line, this.background equals new Sprite(this, 'images/background.png'); creates a background sprite. The line, this.sprites[this.sprites.length] equals this.background; adds the background sprite to the sprite list. The line, async gameInitialize() is the method to load all the sprite images. The line, var promiseList equals []; makes a promise list."

The screenshot displays source code for CrackerChaseGame code. The line, for (let sprite of this.sprites) { works through the sprites in the game. The line, await Promise.all(promiseList); waits for the sprites to finish loading. The line, gameStart() { starts the game. The line, window.requestAnimationFrame(this.gameUpdate.bind(this)); starts the game animation.

CODE ANALYSIS

The CrackerChaseGame class

The code above defines the class that will implement our game. You might have some questions about it.

Question: How does the game pass a reference to itself to the sprite constructor?

Answer: We know that when a method in a class is called, the this keyword represents a reference the object within which the method is running. In a method which is part of the CrackerChaseGame class the keyword this represents a reference to the CrackerGameClass instance. We can pass the value of this into other parts of the game that need it:

Click here to view code image

this.background = new Sprite(this, 'images/background.png');

The code above makes a new Sprite instance and sets the value of the game argument to this so that the sprite now knows which game it is part of.

Question: Why does the game call the draw method on the sprite to draw it? Can’t the game just draw the image held inside the sprite?

Answer: This is a very important question, and it comes down to responsibility. Should the sprite be responsible for drawing on the screen, or should the game do the drawing? I think drawing should be the sprite’s job because it gives the developer a lot more flexibility.

For instance, adding smoke trails to some of the sprites in this game by drawing “smoke” images behind the sprite would be much easier to do if I could just add the code into the “smoky” sprites rather than the game having to work out which sprites needed smoke trails and draw them differently.

Question: Does this mean that when the game runs, the entire screen will be redrawn each time, even if nothing on the screen has changed?

Answer: Yes. You might think that this is wasteful of computer power, but this is how most games work. It is much easier to draw everything from scratch than it is to keep track of changes to the display and only redraw parts that have changed.

Starting the game

Now that we have our game class, we can start the game running. Below is the body of the HTML document for the game. It contains a canvas, and the <body> element has an onload attribute that calls the JavaScript function doGame when the page is loaded.

Click here to view code image

<body onload="doGame()">
  <canvas id="canvas" width="800" height="600">
    This browser does not support a canvas.
  </canvas>
</body>

Click here to view code image

async function doGame() {
    var activeGame = new CrackerChaseGame();
    await activeGame.gameInitialize();
    activeGame.gameStart();
}

Below, you can see the gameStart method. The first statement calls the gameReset method to reset the game and make it ready to play. The second statement calls window.requestAnimationFrame to connect the gameUpdate method to the next screen animation event. We need to have a detailed look at the code here because it tells us some important things about the this reference.

Investigating this

We started using the this reference when we created the stock storage objects in the Fashion Shop application in Chapter 10. We discovered that in a method inside a class the keyword this means “a reference to the object that this method is running inside.” If this seems confusing, consider the sequence of statements that are being performed. The function doGame contains the following statement to start the game running:

activeGame.gameStart();

The statement means “follow the reference activeGame to an object and call the gameStart method on that object.” The JavaScript system finds the object and calls the gameStart method in it. Just before it runs the code in gameStart, the JavaScript system sets the keyword this to refer to the same object as activeGame. The gameStart method contains the statement:

this.gameReset();

The statement follows the this reference (which is referring to the activeGame object) and then calls the method gameReset on that object. So everything works as it should, and the correct game object is reset and ready for play. The reference this.gameUpdate refers to the game update method that we want to have called to update our game. So you might think that we can just pass the method reference into the window.requestAnimationFrame method as a parameter.

Click here to view code image

window.requestAnimationFrame(this.gameUpdate);

The problem is that the code above does not work because the gameUpdate method will not be called from a reference to the activeGame object. It is called by the JavaScript window object when it is time to redraw the display. In other words, the this reference inside gameUpdate will refer to the wrong thing when the function runs. We can fix this by explicitly binding the this reference in the call of gameUpdate to a reference to the active game object:

Click here to view code image

window.requestAnimationFrame(this.gameUpdate.bind(this));

The bind part of the call above is highlighted. It explicitly says to JavaScript “When you call the gameUpdate function, make the value of this in the gameUpdate the same as the value of this in the gameReset function.” You might find this confusing. I certainly did. It helps to remember just who is calling the gameUpdate function. It is not called via a reference to a game object; it is called from within the window object. The result is that it can’t have a this reference to the active game at the point it runs. So we need to explicitly bind in a value of this for the method to use. If you run the example program in the Ch12 Creating Games\Ch12-15 Background Display folder, you will see the background displayed.

Add a cheese sprite

The player sprite will be a piece of cheese that is steered around the screen. We’ve seen how a game can respond to keyboard events; now we’ll create a player sprite and get the game to control it. The Cheese class below implements the player object in our game.

Click here to view code image

class Cheese extends Sprite {
    constructor(game, url) {
        super(game,url);

        this.width = game.canvasWidth / 15;
        this.height = game.canvasWidth / 15;

        this.speed = 5;
        this.xSpeed = 0;
        this.ySpeed = 0;

        window.addEventListener("keydown", (event) => {
            switch(event.code){
                case 'ArrowLeft':
                    this.xSpeed = -this.speed;
                    break;
                case 'ArrowRight':
                    this.xSpeed = this.speed;
                    break;
                case 'ArrowUp':
                    this.ySpeed = -this.speed;
                    break;
                case 'ArrowDown':
                    this.ySpeed = this.speed;
                    break;
            }
        });
        window.addEventListener("keyup", (event) => {
            switch(event.code){
                case 'ArrowLeft':
                    this.xSpeed = 0;
                    break;
                case 'ArrowRight':
                    this.xSpeed = 0;
                    break;
                case 'ArrowUp':
                    this.ySpeed = 0;
                    break;
                case 'ArrowDown':
                    this.ySpeed = 0;
                    break;
            }
        });
    }

    update(){
        super.update();

        this.x = this.x + this.xSpeed;
        this.y = this.y + this.ySpeed;

        if(this.x<0) this.x=0;
        if(this.x + this.width > this.game.canvasWidth){
            this.x = this.game.canvasWidth - this.width;
        }

        if(this.y<0) this.y=0;
        if(this.y + this.height > this.game.canvasHeight){
            this.y = this.game.canvasHeight - this.height;
        }
    }

    draw() {
        this.game.context.drawImage(this.image, this.x, this.y, this.width, this.height);
    }
}

CODE ANALYSIS

Player sprite

The code above defines the Cheese sprite. You can find it in the Ch12 Creating Games\Ch12-16 Background and Cheese sample code folder. Use your browser to open the web page there.

You can use your cursor to move the cheese around the canvas. Note what happens when your cheese reaches the edge of the canvas. You might have some questions about this.

Question: Why does the Cheese object have width and height properties?

Answer: Unless you specify otherwise, an image is drawn with the size of the original resource. The playfield image is 800 pixels wide and 600 pixels high and fits the canvas perfectly. However, I want to be able to control the size of the cheese sprite so that I can vary the game play. If we find out during testing that the players would like a larger cheese, I want to make this as easy as possible. Use this code to change the size of the cheese to one-fifteenth of the screen width:

Click here to view code image

this.width = game.canvasWidth / 15;
this.height = game.canvasWidth / 15;

At the moment this is done, the drawImage function can draw an image in a particular width, so the Cheese class overrides the draw method in the parent Sprite class.

Click here to view code image

draw() {
    this.game.context.drawImage(this.image, this.x, this.y, this.width, this.height);
}

This also makes it possible for the game to change the size of the cheese during the game.

Question: How does the program stop the cheese from moving off the screen?

Answer: If you try to steer the cheese off the screen with the arrow keys, you will find that you can’t. The image above shows how this works. The game knows the position of the cheese and the width and height of the canvas. If the x position plus the width of the cheese is greater than the width of the screen (as it is in the image above), the update method for the cheese will put the cheese back on the right edge:

Click here to view code image

if(this.x + this.width > this.game.canvasWidth){
    this.x = this.game.canvasWidth - this.width;
}

The cheese update method also makes sure that the cheese cannot be moved off the other edges of the canvas. The game also uses the width and height properties to place the cheese in the middle of the canvas at the start of the game.

Click here to view code image

reset() {
    this.x = (this.game.canvasWidth - this.width) / 2.0;
    this.y = (this.game.canvasHeight - this.height) / 2.0;
}

Add a Cracker sprite

Moving the cheese around the screen is fun for a while, but we need to add some targets for the player. The targets are crackers the player must capture with the cheese. When a cracker is captured, the game score is increased, and the cracker moves to another random position on the screen. The Cracker sprite is a subclass of the Sprite class:

Click here to view code image

class Cracker extends Sprite {

    constructor(game, url) {
        super(game, url);

        this.width = game.canvasWidth / 20;
        this.height = game.canvasWidth / 20;
    }

    getRandomInt(min, max) {
        var range = max - min + 1;
        var result = Math.floor(Math.random() * (range)) + min;
        return result;
    }

    reset() {
        this.x = this.getRandomInt(0, this.game.canvasWidth-this.width)
        this.y = this.getRandomInt(0, this.game.canvasWidth-this.height)
    }

    draw() {
        this.game.context.drawImage(this.image, this.x, this.y, this.width, this.height);
    }
}

The Cracker class is very small because it gets most of its behavior from its superclass, the Sprite class. The constructor sets the width of a cracker to a 20th of the screen size. The reset method for the cracker picks a random location on the canvas. It uses the same random number function that we used to position dots in the art program. We can add a Cracker to our game by creating it and then adding it to the list of sprites in the game:

Click here to view code image

this.sprites = [];

this.background = new Sprite(this, 'images/background.png');
this.sprites[this.sprites.length] = this.background;

this.cracker = new Cracker(this, 'images/cracker.png');
this.sprites[this.sprites.length] = this.cracker;

this.cheese = new Cheese(this, 'images/cheese.png');
this.sprites[this.sprites.length] = this.cheese;

The sample in the Ch12 Creating Games\Ch12-17 Cheese and Cracker folder shows how this works. See Figure 12-5.

Figure 12-5 Cheese and cracker

Add lots of crackers

We would like to have 30 crackers in the game for the player to chase after. It turns out that this is very easy to do. We can use a loop to create crackers and add them to the sprite list.

Click here to view code image

for (let i = 0; i < 30; i = i + 1) {
    this.sprites[this.sprites.length] = new Cracker(this, 'images/cracker.png');
}

Figure 12-6 shows the game now. If we want to have even more crackers, we just need to change the limit of the range in the for loop that creates them. The sample in the Ch12 Creating Games\Ch12-18 Cheese and Crackers folder contains this code. If you run the sample, you will see a screen full of crackers that a player can move the cheese over.

Figure 12-6 Cheese and crackers

Catch the crackers

The game now has lots of crackers and a piece of cheese that can chase them. But nothing happens when the cheese “catches” a cracker. We need to add a behavior to the Cracker that detects when the cracker has been “caught” by the cheese. A cracker is caught by the cheese when the cheese moves “on top” of it. The game can detect when this happens by testing whether rectangles enclosing the two sprites intersect.

Figure 12-7 shows the cheese in the process of catching a cracker. The rectangles around the cheese and cracker images are called bounding boxes. When one bounding box moves “inside” another, we say that the two are intersecting. When the cracker updates, it will test to see whether it intersects with the cheese. The cheese is intersecting with the cracker because the right and bottom edges are “inside” the cheese.

Figure 12-7 Intersecting sprites

Figure 12-8 shows how the test will work. In this figure, the two sprites are not intersecting because the right edge of the cheese is to the left of the left edge of the cracker. In other words, the cheese is too far to the left to intersect with the cracker. This would also be true if the cheese were above, below, or to the right of the cracker.

Figure 12-8 Nonintersecting sprites

We can create a method that tests for these four situations. If any of them are true, the rectangles do not intersect.

Click here to view code image

intersectsWith(sprite) {
    if ((this.x + this.width) < sprite.x) return false;
    if ((this.y + this.height) < sprite.y) return false;
    if (this.x > (sprite.x + sprite.width)) return false;
    if (this.y > (sprite.y + sprite.width)) return false;
    return true;
}

The method can be added to the Sprite class. The method returns true if the sprite intersects with a particular target. We add this method to the Sprite class so that all sprites can use it. Now we can add an update method to the Cracker class that checks to see whether the cracker intersects with the cheese:

Click here to view code image

update() {
    if (this.intersectsWith(this.game.cheese)) {
        this.reset();
    }
}

When the cheese moves over a cracker, it is reset to a different position in the screen. The sample in the Ch12 Creating Games\Ch12-19 Eating Crackers folder contains this code. If you run the sample, you will see a screen full of crackers that a player can move the cheese over. When the cheese is moved over a cracker, the cracker disappears and is redrawn somewhere else on the screen.

Add sound

At the moment our game is silent, which is a bit boring. We could improve the cracker class so that it plays a sound when it is eaten. We’ve made JavaScript programs that play sound in the past. We added a sound element to the egg timer in Chapter 2. Our game can make sound by using an Audio object:

The constructor for the Cracker class now accepts an additional parameter giving the URL that specifies the location of the sound resource. When the Cracker constructor runs, it creates an Audio object for the sound effect and then sets the src property of the new Audio object to the sound resource location.

Click here to view code image

this.cracker = new Cracker(this, 'images/cracker.png', 'sounds/burp.wav');

When the cracker is created, the constructor is given a path to the sound file to be used. The update method can now play the sound whenever the cheese “eats” a cracker:

You can find the noisy version of the game in the Ch12 Creating Games\Ch12-20 Eating with sound example folder. If you want to create your own sound effects, you can use the program Audacity to capture and edit sounds. It is a free download from http://www.audacityteam.org/ and is available for most types of computers.

Adding scores

Keeping score is another great way to motivate the player of a game. In Cracker Chase, the player will increase their score by 10 each time they eat a cracker.

The Cracker update method above adds 10 to the score in the game each time a cracker is eaten. The score value is held in the CrackerChaseGame class and is drawn each time the screen is updated:

The source code for fillStyle and fillText methods. The line, this.context.font = "40px Arial"; sets the font and size for the score display. The line, this.context.fillStyle = "red"; sets the color for the score display. The line, this.context.fillText("Score: " + this.score, 10, 40); draws the score.

We draw the score on the canvas using a set of methods from the canvas context that we’ve not seen before. The fillText method draws filled text on the screen. The fillStyle method lets us set the color of the text, and we can set the text size and style by assigning a value to the font property of the context.

Figure 12-9 shows how the score is displayed. You can find the scoring version of the game in the Ch12 Creating Games\Ch12-21 Eating with scores example folder.

Figure 12-9 Score display

WHAT COULD GO WRONG

Bad collision detection

There are some problems with using bounding boxes to detect collisions. The image above shows that the cheese and the cracker are not colliding, but the game will think that they are. This should not be too much of a problem for our game. It makes it easier for the player, as they don’t always have to move the cheese right over the cracker to score a point. However, the player might have grounds for complaint if the game decides they have been caught by a killer tomato because of this issue. There are a few ways to solve this problem:

When the bounding boxes intersect (as they do above), we could check the intersecting rectangle (the part where the two bounding boxes overlap) to see if they have any pixels in common. Doing so provides very precise collision detection, but it will slow down the game.

We could make the bounding boxes slightly smaller so that they don’t overlap as much.

We could detect collisions using distance rather than intersection, which works well if the sprites are mostly round.

The final solution is the one I like best. I could make all the game images rectangular, so the sprites fill their bounding boxes, and the player always sees when they have collided with something.

PROGRAMMER’S POINT

When you write a game, you control the universe

One of the reasons I like writing games so much is that I have complete control of what I’m making. If I’m solving a problem for a customer, I must deliver certain outcomes. But in a game, I can change what it does if I find a problem. I can also redefine the gameplay if I make a mistake in the program. Sometimes, this produces a more interesting behavior than the one I was trying to create. This has happened on a number of occasions.

Add a killer tomato

Currently, the game is not much of a game. There is no jeopardy for the player. When you make a game, you set up something that the player is trying to achieve. Then you add some elements that will make this difficult for them. In the case of the game Cracker Chase, I want to add “killer tomatoes” that will relentlessly hunt down the player. As the game progresses, I want the player to be chased by increasing numbers of tomatoes until the game becomes all about survival. The tomatoes will be interesting because I’ll give them “artificial intelligence” and physics.

Add “artificial intelligence” to a sprite

Artificial intelligence sounds difficult to achieve, but in the case of this game, it is actually very simple. At its heart, artificial intelligence in a game simply means making a program that would behave like a person in that situation. If you were chasing me, you’d do this by moving toward me. The direction you would move would depend on my position relative to you. If I were to your left, you’d move left, and so on. We can put the same behavior into our killer tomato sprite:

Click here to view code image

if(this.game.cheese.x > this.x){
    this.xSpeed = this.xSpeed + this.acceleration;
}
else {
    this.xSpeed = this.xSpeed - this.acceleration;
}

if(this.game.cheese.y > this.y){
    this.ySpeed = this.ySpeed + this.acceleration;
}
else {
    this.ySpeed = this.ySpeed - this.acceleration;
}

This condition shows how we can make an intelligent killer tomato. It compares the x positions of the cheese and the tomato. If the cheese is to the right of the tomato, the x speed of the tomato is increased to make it move to the right. If the cheese is to the left of the tomato, it will accelerate in the other direction. The code above then repeats the process for the vertical positions of the two sprites. The result is a tomato that will move intelligently toward the cheese. We could instead make a “cowardly” tomato that runs away from the player by making the acceleration negative so that the tomato accelerates in the opposite direction of the cheese. This would be useful for games where the player has to chase down targets.

PROGRAMMER’S POINT

Making game elements “intelligent” makes games much more interesting

Artificial intelligence (AI) is the field of computing that aims to make software that can do things that normally require human intelligence. Making a “killer tomato” that always chases the cheese is not necessarily creating AI, but it is a great way to make gameplay more interesting for the player. It gets especially interesting if you have a number of different objects with different “intelligent” behaviors for the player to deal with.

Add physics to a sprite

Each time the game updates, it can update the position of the objects on the screen. The amount that each object moves each time the game updates is the speed of the object. When the player is moving, the cheese’s position is updated by the value 5. In other words, when the player is holding down a movement key, the position of the cheese in that direction is being changed by 5. The updates occur 60 times per second because this is the rate at which the game loop runs. In other words, the cheese would move 300 pixels (60*5) in a single second. We can increase the speed of the cheese by adding a larger value to the position each time it is updated. If we used a speed value of 10, we’d find that the cheese would move twice as fast.

Acceleration is the amount that the speed value is changing. The statements below update the xSpeed of the tomato by the acceleration and then apply this speed to the position of the tomato.

Click here to view code image

this.xSpeed = this.xSpeed + this.acceleration;
this.x = this.x + this.xSpeed;

The initial speed of the tomato is set to zero, so each time the tomato is updated, the speed (and hence the distance it moves) will increase. If we do this in conjunction with “artificial intelligence,” we get a tomato that will move rapidly toward the player.

Add friction to a sprite

If we just allowed the tomato to accelerate continuously, we’d find that the tomato would just get faster and faster, and the game would become unplayable. The statement below adds some “friction” to slow down the tomato. The friction value is less than 1, so each time we multiply the speed by the friction, it will be reduced, which will cause the tomato to slow down over time.

Click here to view code image

this.xSpeed = this.xSpeed * this.friction;

The friction and acceleration values are set in the constructor for the Tomato sprite:

Click here to view code image

constructor(game, imageUrl) {
    super(game, imageUrl);

    this.width = game.canvasWidth / 12;
    this.height = game.canvasWidth / 12;
    this.acceleration = 0.1;
    this.friction = 0.99;
}

After some experimentation, I came up with the acceleration value of 0.1 and a friction value of 0.99. If I want a sprite that chases me more quickly, I can increase the acceleration. If I want the sprite to slow down more quickly, I can increase the friction. You can have a lot of fun playing with these values. You can create sprites that drift slowly toward the player and, by making the acceleration negative, you can make them run away from the player. You can have some fun avoiding the killer tomato with the game example in the Ch12 Creating Games\Ch12-22 Killer tomato folder.

PROGRAMMER’S POINT

When you write a game, you can always cheat

When you’re writing a game, you should always start with the simplest, fastest way of getting an effect to work and then improve it if necessary.

The “physics” that I’m using are not really an accurate simulation of physical objects. The way that I’ve implemented friction is not very realistic, but it works and gives the player a good experience. I find it interesting that six or seven lines of JavaScript can make something that behaves in such a believable way. The Cracker Chase game uses very simple collision detection, a form of artificial intelligence, and physics, but it is still fun to play. It really feels as if the tomatoes are chasing you. Making the physics model completely accurate would take a lot of extra work and would add very little to the gameplay.

Create timed sprites

It’s important that a game be progressive. If the game started with lots of killer tomatoes, the player would not last very long and would not enjoy the experience. I’d like the first tomato to appear after five seconds and a new tomato to appear every 10 seconds after that. We can do this by giving each tomato an “entry delay” value when we construct it:

Click here to view code image

for (let tomatoCount = 0; tomatoCount < 5; tomatoCount = tomatoCount + 1) {
    let entryDelay = 300 + (tomatoCount * 600);
    this.sprites[this.sprites.length] =
        new Tomato(this, 'images/tomato.png', entryDelay);
}

This code uses a loop to create 5 tomato sprites with delay values starting at 300 and going up in steps of 600. The constructor in the Tomato class stores the value of entryDelay for that tomato.

The entryDelay value is used to delay the entry of the sprite:

Click here to view code image

update() {

    this.entryCount = this.entryCount + 1;

    if (this.entryCount < this.entryDelay) {
        return;
    }

    .. the rest of the update method goes here
}

The update method is called 60 times per second. The first tomato has an entry delay of 300, which means that it will arrive at 300/60 seconds, which is 5 seconds after the game starts. The next tomato will appear 10 seconds after that, and so on, up until the last one. When I played the game with 5 tomatoes chasing me, I noticed that the gameplay was not very thrilling because all the sprites merged into one another, making them very easy to avoid. This is because they were all accelerating at the same rate. To fix this, I used the entry delay to calculate a change to the acceleration. This means that the later sprites accelerate more quickly and don’t bunch together.

The example program in the Ch12 Creating Games\Ch12-22 Killer tomatoes folder shows how this works. It can get rather frantic after a few tomatoes have turned up and are chasing you.

Complete the game

We now have a program that provides some gameplay. Now we need to turn this into a proper game. To do so, we need to add a start screen, provide a way that the player can start the game, detect and manage the end of the game, and then add a high score because it adds a lot to the gameplay.

Add a start screen

A start screen is where the player will—you guessed it—start the game. When the game is complete, the game returns to the start screen. Figure 12-10 shows the start screen for this game.

Figure 12-10 Start screen

The image shows the start screen of the game. The title "Cracker Chase" and the high score are displayed on the top. The content reads, "Welcome to cracker chase. Steer the cheese to capture the crackers. Beware the killer tomatoes. Arrow keys to move and Press G to play."

PROGRAMMER’S POINT

Make sure you tell people how to play your game

In my long and distinguished career in computing, I’ve judged quite a few game development competitions. I’ve lost count of the number of games that I’ve tried to play and failed because the game doesn’t tell me what to do. The problem is usually that everyone focuses on making the game and not on telling people how to play it. Failing at a game while you work out which keys you are supposed to press doesn’t make for a very good introduction to it, so make sure that you make the instructions clear and present them right at the start.

The drawStartScreen method draws the start screen. It uses a helper function called displayMessage that centers text on the screen.

Click here to view code image

drawStartScreen(){
    this.background.draw();
    this.context.font = "50px Arial";
    this.displayMessage("Cracker Chase",70);
    this.context.font = "40px Arial";
    this.displayMessage("High score: " + this.topScore, 110);
    this.displayMessage('Welcome to Cracker Chase', 240);
    this.displayMessage('Steer the cheese to capture the crackers', 280);
    this.displayMessage('BEWARE THE KILLER TOMATOES',320);
    this.displayMessage('Arrow keys to move', 470);
    this.displayMessage('Press G to play', 520);
}

We saw the screen drawing methods earlier when we added code to the update method that drew the score on the screen. The displayMessage method also uses the measureText method to get the width of the text so that it can be centered on the screen. It draws the text twice. The first time, the text is drawn in black, and then the text is drawn again in red. The second time the text is drawn, it is moved slightly to make it appear that the black text is a shadow.

The source code of the displayMessage method is shown. The line, var textSize = this.context.measureText(text); measures the size of the text message. The line, var x = (this.canvasWidth-textSize.width)/2.0; calculates the offset to center the text. The line, this.context.fillStyle = "black"; sets the text to black. The line, this.context.fillText(text, x, yPos); draws the text background. The line, this.context.fillStyle = "red"; sets the text to red. The line, this.context.fillText(text, x+2, yPos+2); draws the text slightly offset.

PROGRAMMER’S POINT

Don’t worry about making the graphics hardware work for you

You might think it’s rather extravagant to draw all the text on the screen twice just to get a shadow effect. However, modern graphics hardware is perfectly capable of many thousands of drawing operations per second. I’ve been known to draw text 20 times just to get a nicely blurred shadow effect behind it. If you think something might look good, my advice is to try it and only worry about performance if the game seems to run very slowly after you’ve done it.

Start the game running

The start screen in Figure 12-10 tells the player to press the G key to start the game. So now we need to add the code to make this happen.

The gameStart method is called when the user starts the game. It calls drawStartScreen to draw the start screen and then binds an arrow function to the keydown event. The arrow function checks for the 'KeyG' key and calls the gameRun method if the gameRunning property of the game is false.

The gameRun method runs the game, sets gameRunning to true, and then triggers the first animation frame in the game. When the game is running, the gameUpdate method updates the sprites and then checks to see if any of them have ended the game. If the game is over, it displays the start screen and the final game score:

Detect the game end

We’ve seen that the game has two states, which are managed by the gameRunning property. This property is set to true when the game is running and false when the start screen is displayed. Now we need to create the code that manages the gameRunning value. The game ends when the player collides with a killer tomato, which is detected in the update method for the tomato sprite:

Click here to view code image

update() {
    // update the tomato here
    if (this.intersectsWith(this.game.cheese)) {
        this.game.gameEnd();
    }
}

The test in the update method for the Tomato sprite checks to see if this tomato intersects the cheese. If it does gameEnd method is called to end the game.

The gameEnd method sets gameRunning to false. It also updates the highScore value. If the current score is greater than the highest score so far, it is updated to the new high score. The value of the high score is displayed on the start screen of the game.

PROGRAMMER’S POINT

Always make a playable game

Something else I noticed while judging game development competitions was that some teams would produce a brilliant piece of gameplay but not attach it to a game. You’d start playing the game and find that it never actually ended. You should make sure that your game is a complete game from the very start. The game should have a beginning, middle, and end. As you have seen in this section, it’s easy to do this, but when people start making a game, they seem to leave it to the last minute to create the game start screen and the game ending code, so that what they produce is not a game. Instead, it is more of a technical demo, which is not quite the same thing. Making your game into a proper game right from the start also makes it much easier for people to try it and then give you feedback.

You can find the completed game in the Ch12 Creating Games\Ch12-24 Complete Crackerchase folder. It’s fun to play for short bursts, particularly if there are a few of you trying to beat the high score. My highest score so far is 740, but then I never was any good at playing video games.

MAKE SOMETHING HAPPEN

Build your own game

The Cracker Chase game can be used as the basis of any sprite-based game you might like to create. You can change the artwork, create new types of enemies, make the game two-player, or add extra sound effects. When I said at the start of this book that programming is the most creative thing you can learn to do, this is the kind of thing I was talking about. You can create a game called “Closet Frenzy” where you are chased around by coat hangers while you search for a matching sock. You could create “Walrus Space Rescue,” where you must steer an interplanetary walrus through an asteroid minefield. Anything you can think up, you can build. However, one word of caution. Don’t have too many ideas. I’ve seen lots of game development teams get upset because they can’t get all their ideas to work at once. It is much more sensible to get something simple working and then add things to it later.

Now that you know how a game works, you can take a look at some game engines, which do a lot of the hard work for you. The Phasor game engine is a great place to start, with many example games you can use as starting points. You can find it at https://phaser.io. If you want to create multiplayer games, you should take a look at Socket.io, which you can use to create a game that is hosted on a Node.js server and can be played by people all over the world. You can find it at https://socket.io/.

What you have learned

An HTML document can contain a canvas element within which items can be drawn at arbitrary positions.

JavaScript can draw Image objects on a canvas at a particular position and of a particular size.

JavaScript images are loaded asynchronously. The onload event will fire when an image is loaded. This can be used to create a Promise object to manage a load.

A number of simultaneous promises can be placed in a list and resolved with a single call of Promise, all of which generates a promise that returns when all the promises in the list have been fulfilled.

An asynchronous JavaScript function (one which has been declared with async) can use the await keyword to await the result of a promise. The asynchronous function is suspended while the result of the promise is awaited. Suspended functions do not block browser execution.

Animation in a game is achieved by repeated redrawing of the game screen. The window.requestAnimationFrame method allows a game to bind a function call to the screen redraw event in the browser.

A game can bind to window events including keyup and keydown events that produce events specifying which keyboard key has been pressed or released. Keyboard events do not necessarily indicate that a printable character has been entered. There are events for Shift and Control keys, which all have characteristic names.

It is also possible to bind to an event that indicates that the user has moved their window “focus” to another window—at which point, a game should stop updating.

The display of a game can be made up of sprites. A sprite is an object that has an associated image, position, and perhaps other properties such as speed and acceleration.

A class hierarchy containing a Sprite superclass and game object subclasses is a good way to manage the objects in a game. A class can also be used for the game itself. The game class contains a list which holds all the sprites as well as properties that indicate the state of the game.

The this reference to be used in a function body can be bound to a specific reference by adding bind information to the call of the function. This technique is especially useful when functions are to be called by external frameworks (such as the browser window object) and you want to set the context of the function call to be an object in your application.

Sprites in a game can be given simple physics and “artificial intelligence” that allows them to interact with the player and make the game much more interesting.

Hopefully, you’ve also taken a few ideas of your own and used them to create some more games.

Here are some points to ponder about game development:

What does await do?

Await is a way of allowing a function to return “early” if code in the function must perform an operation that will take a long time. To understand how this works, imagine if I had the power to make copies of myself. When I went shopping, I could select all the items I wanted to buy, make a duplicate Rob, and then send him to pay for the items and bring them home. I could go home and get on with something more interesting. At some point in the future, “duplicate Rob” would turn up with my shopping.

The await keyword works in exactly the same way. When execution reaches an await statement, a new process is created, which will wait for the awaited promise to be fulfilled. In the meantime, execution returns from the function containing the await. When the awaited promise is fulfilled, the process then moves on to the statement in the function after the awaited one. This continues until the process reaches the end of the function, at which point the process is destroyed.

Functions that contain awaited operations are called “asynchronous.” We don’t know when they will finish executing. With a normal function, we know that when the function returns it has performed all the statements in the function. However, an asynchronous function will return before any awaited actions have finished. In other words, completion of the function is not synchronized with the call. For this reason, we need to mark functions that contain await as async.

Can a function contain multiple awaits?

Yes, it can. Each awaited statement is awaited in turn as the function is performed.

Must a function that is called asynchronously always perform an awaited action?

No. Sometimes when a function runs, it might decide that the awaited action cannot be performed, so it can return without awaiting anything. However, marking a function as async makes it slightly less efficient to call, so you should only mark a function as async if it contains await.

Can an anonymous function contain awaits?

Yes, it can. However, the declaration of the anonymous function must be preceded by the async keyword to mark the anonymous function as asynchronous.

Can you draw any HTML element on a canvas?

No. An HTML document brings together a collection of HTML elements. However, when an object is drawn on a canvas all that happens is that a particular path or image is rendered onto that canvas. The commands to set the format of drawing actions (for example select a font or fill style to be used) look very similar to attributes that you might add to an HTML element. However, these commands just control the drawing operation, not the properties of an object in the canvas.

Can a page contain multiple HTML canvases?

Yes. A JavaScript program could hold several context references that can be used to draw on different canvases.

Will the browser slow down if I draw a lot on the canvas?

Yes, it will slow down eventually. However, modern browsers are very good at drawing graphics, so you will have to draw something very complicated for this to be noticeable.

How would I create an attract mode for my game?

Many games have an “attract mode” screen as well, which displays some gameplay. Currently, our game just has two states that are managed by the Boolean gameRunning property. We could use an integer to hold a range of states, including “attract mode.” We could make an “AI player” who moved the cheese around the screen in a random way and then just run the game with the random player at the controls. We could add an “attract mode” behavior to the tomatoes so that they were aiming for a point some distance from the player, to make the game last longer in demo mode.

How could I make the gameplay the same each time the game is played?

The game uses the JavaScript random number generator to produce the position of the crackers, which means each time the game runs, the crackers are in a different position. We could replace this with a random number generator that always produced the same sequence of numbers, or we could add a table of fixed positions that could be used to place the crackers. This would mean that the crackers would be drawn and would respawn in the same sequence each time the game was played. A determined player could learn the pattern and use this to get a high score.

Is the author of the game always the best person at playing it?

Most definitely not. I’m often surprised how other people can be much better than me at playing games I’ve created. Sometimes, they even try to help me with hints and tips about things to do in the game to get a higher score.

Index

Symbols

* (asterisk) character, 52, 101

\ (backslash) character, 120, 141

` (backtick) character, 119, 141, 143

= (equals) character, 47, 107

+ (plus) operator, 111, 119, 120

; (semicolon) character, 76

{ } (curly braces), 161, 173, 288, 296, 319

[ ] (square brackets), 189, 288, 296, 319

" (double quote) character, 119, 141, 143

' (single quote) character, 119, 141, 143

A

<a> tag, 41–42

about this book, xv–xvii

abstraction, 305, 344–345

acceleration values, 458

activeGame object, 442

addEventListener method, 429

adding machine program, 122, 124–126

addition service, 398, 399–400

addStock function, 361–362

alert function, 12, 52, 213

alertInputText ID, 46

aligning text, 71, 88

alternative text, 39

analyzing data, 370–371

Andreessen, Marc, 28

animating images, 427–429

anonymous functions

awaits contained in, 468

code analysis of, 375–376

explanation of, 374, 402, 405

simplifying promises using, 383

appendChild method, 200

applets, 5

applications

adding machine, 122, 124–126

data-processing, 96–97

digital dice, 222–232, 236

egg timer, 52–56

fashion shop, 335–363, 368–379

ice cream sales, 242–269

multiplication table, 196–203

pizza calculator, 127–131

ride selector, 161–172, 178–196

temperature conversion, 130–131

ticking clock, 72–77

tiny contacts, 276–316

totalizer, 133–137

weather information, 379–387

See also programs

arc drawing method, 417

arguments

arrays of, 221

code analysis of, 214–216

maximum number of, 238

ordering of, 18

parameters and, 216–217

references used as, 219–220

arrays, 221, 246–251

bounds of, 271

code analysis of, 267–268

counting from zero in, 249

filter method, 377

investigating and creating, 246–248

as lookup tables, 265–266

map method, 378–379

processing data in, 249–251

reduce method, 378

size of, 268, 271

sorting data in, 371–373

storing data in, 246–248, 281–283

arrow functions, 374–375, 376, 402, 405, 463

artificial intelligence (AI), 456–457

artwork

computer-generated, 414–419

drawing on canvas, 410–413, 419–425

assign function, 356

assignment operation, 46

asterisk (*) character, 52, 101

async keyword, 424–425, 426

asynchronous operations, 380, 420

attract mode for games, 468

attributes

data, 184–188

image tag, 38

properties vs., 60

style, 64, 80, 87

Audacity program, 453

audio

adding, 55, 140, 452–453

playback control, 56, 140

audio element, 55, 56

await keyword, 424–425, 426, 467–468

Azure account, 401

B

backslash (\) character, 120, 141

backtick (`) character, 119, 141, 143

bad nesting, 37

Berners-Lee, Tim, 28

binary representation, 104

binding event handlers, 421

bits, 103, 104

block-copy commands, 342

blocks of statements

for loop and, 193

if construction and, 160–161

blur event, 435

Boolean expressions, 149–150

Boolean function, 147, 149

Boolean values, 146–149, 173, 174

bounds of the array, 271

<br> tag, 31, 34

bracket notation, 300, 317

break keyword, 171

breakpoints, setting, 262

browsers. See web browsers

bugs

faults vs., 67, 181

fixing in programs, 181–183

responding to reports of, 181

See also errors

buildElementsFromSchema method, 358

buttons, creating HTML, 42–44

C

C# and C++ programming languages, 4, 346

calculations

examples of, 10–12

performing, 110–112, 244–245

calling functions, 208, 209, 210–211

camel case, 108

canvas, 410–425

computer art program, 414–419

coordinates, 413–414

drawing on, 410–413, 419–425, 468

cascading styles, 85–86, 88

case sensitivity, 310, 317

catch block, 326, 327, 328

catch method, 384, 386, 426

changeArrayElement function, 267

children property, 189

class attribute, 82, 84, 90

classes, 335, 363–364, 365

constructor method for, 339–340, 342

diagram created for, 343–344

game sprite, 438, 440–441

hierarchy of, 345, 347–348

inheritance mechanism for, 343–344, 345–347

method members added to, 348–349

object-oriented design and, 341–342

static members of, 352–355, 357

style, 82, 84

className property, 180

cloning repositories, 18–19

code

avoiding repeated, 343

bugs vs. faults in, 67, 181

building web pages from, 196–201

debugger for running, 260–264

finding and fixing bugs in, 181–183

importance of well-designed, 183–184

code analysis, xvi

addition service, 399–400

anonymous functions, 375–376

arguments, 214–216

arrays, 267–268

Boolean values, 147–149

code errors and testing, 109–110

commands and responses, 10–12

comparison operators, 151–152

doSave function, 286–287

doShowAlert function, 47–48

evaluating expressions, 100–102

exception handling, 327–330

findContacts function, 284

floating-point values, 114–115

for loop, 192–194

functions, 209–212

game class, 440–441

getNumberFromElement function, 230–231

HTML from JavaScript, 199–201

if constructions, 160

input generation, 256–257

JSON, 299

keyboard events, 430–431, 432–433

logical operators, 154–156

multiple path use, 394–396

performing calculations, 112

player sprite, 445–446

promises, 385–387

reading numbers, 259–260

server use, 390–392

sorting items, 372–373

Super Search, 314–315

ticking clock program, 75

whole vs. real numbers, 113

collections

arrays as, 221

for-of loop and, 195–196, 221

collision detection, 455

colors

adding, 64–65

creating, 418

keyword, 24

mouse rollover, 66–67

comments

adding to programs, 131–133, 141

HTML, 38, 133

comparison function, 371–372, 373, 374, 402

comparison operators, 150–152

compiled languages, 23, 102

computers

art generated by, 414–419, 440

data processing by, 96–97, 140

minimum requirements for, xvii

concat method, 272

concatenation, 119, 272

confirm function, 334

console.log statement, 192

Console window, 9

const keyword, 332, 354

constructive laziness, 195

constructor method

class creation and, 339–340, 342

objects and, 340–341

contacts app, 276–316

displaying contacts in, 285

finding contacts in, 283–285, 287, 309–315

helper functions, 280–281

JSON for encoding data in, 295–298

local storage for, 292–295

objects used in, 291–292

property accessors in, 300–304

prototype creation, 277–280

saving contacts in, 285–287

schemas created for, 304–308

storing contacts in, 281–283

Super Search feature for, 310–315

user ideas for improving, 310, 316

container element, 306

control variables, 191

controller function, 422

coordinates, canvas, 413–414

Cracker Chase game, 436–465

AI added to, 456–457

class definition, 438, 440–441

code analysis, 438, 440–441

collision detection, 455

end detection, 464

game object, 439–440

physics and friction, 457–458, 459

running, 463–464

scores added to, 453–454, 464

sound added to, 452–453

sprites in, 436–438, 443–452, 456–460

start screen added to, 461–462, 463

createElement method, 199, 255, 380

createListElement function, 369–370

createListPage function, 369

createServer method, 389–390, 395, 404

CSS (Cascading Style Sheets), 82, 85–86, 89, 91

See also style sheets

curly braces { }, 161, 173, 288, 296, 319

currentDate variable, 72, 73

D

data

analyzing, 370–371

fetching, 380–385

information vs., 103

sorting, 371–373, 376–377, 402

text vs. numeric, 112

data attributes, 184–188

adding to HTML elements, 184–185

code analysis of, 186–187

data processing

arrays and, 249–251

computers and, 96–97, 140

expressions for, 100–102

JavaScript, 99, 100, 104

programs and, 98–99

data schemas. See schemas

Date object, 72, 149

debugger feature, 260–264

default selector, 170

defining functions, 208, 209–210, 213

delimiters, 119

designing

systems before building, 305, 341–342

user interface for customers, 162, 252–254

Developer view, 7–8

digital dice program, 222–232

double dice version of, 236

error handling added to, 227–232

random number calculations in, 222–226

disabled attribute, 385

displayContact function, 292

displayElementValue function, 280, 285

displaying

images, 57

symbols, 32–33

text, 49–50, 462

displayMessage function, 462

<div> element, 84–85, 88, 90, 253

doAddition function, 9, 124

doAddToTotal function, 136

doBuildPage function, 305, 306, 307

doBuildSalesInputItems function, 253–254, 256

doCalc function, 244–245, 251, 262

doClockTick function, 74, 76–77

Document Object Model (DOM), 45, 252

documents

deleting elements from, 201–202

HTML formatting of, 41

style sheets added to, 80, 88

doEndTimer function, 52, 54

doFind function, 287, 312–313

doGame function, 441

doMouseOver function, 66

doSave function, 285, 286–287

doSaveAdd function, 362

doShowAlert function, 47–48

doStartClock function, 76–77

doStartFashionShop function, 360

doStartTimer function, 52

doStartTinyContacts function, 298

dot notation, 300, 317

double quote (") character, 119, 141, 143

doUpdateItem function, 370

doValidate function, 327, 328

downloads for book, xviii

draw method, 440, 445

drawImage function, 427, 445

drawing

on canvas, 410–413, 419–425, 468

computer-generated, 414–419, 440

drawStartScreen method, 462, 463

E

egg timer program, 52–56

functions used in, 52

investigation exercise, 53–54

sound added to, 55

Eich, Brendan, 5

elements, 37, 46, 58, 246

Elements window, 8

else keyword, 159, 160, 174

<em> tag, 30, 60

em units, 70, 88, 90

emojis, meanings of, 33

empty objects, 288, 300, 316

encapsulation, 234

end method, 392

end tags, 32

entryDelay value, 459–460

equality operator, 151, 152, 153, 174

equals (=) character, 47, 107

error handling

adding to applications, 227–232

JavaScript promises and, 384

errors

exceptions and, 330–334, 363

finding in advance, 228–233

floating-point values and, 114–115

importance of managing, 335

logic, 109–110

spelling, 110

testing for, 110, 126

See also bugs; faults

escape sequences, 120, 141, 143

event handlers, 421

events

attributes of, 87

definition of, 421

keyboard, 430–435

window, 429–430

exceptions

catching, 327

errors and, 330–334, 363, 386

explanation of, 299, 324, 364–365

handling of, 327–330

JSON use of, 299, 324, 325–326

Express system, 401

expressions

Boolean, 149–150

evaluated by JavaScript, 100–102, 111

operators and operands in, 100, 110, 141

processing data with, 100

F

F12 key, 7, 23

false keyword, 146, 147–148

fashion shop application, 335–363, 368–379

adding stock items, 361–362

class hierarchy, 347–348

code exploration, 362

data analysis, 370–371

data storage solutions, 355–356

HTML creation, 359–360

illustrated overview, 335–338

menu options, 361

sorting data, 371–372, 376–377

starting the program, 360

static class members, 352–355

store stock data, 339–340, 368–370

suggestions for expanding, 363

user interface, 357–359, 361

faults

bugs vs., 67, 181

fixing in programs, 181–183

responding to reports of, 181

types of, 330–331

See also errors

fetch function, 381–382, 403, 404

fetching data, 380–385

asynchronous operation for, 380

calling web services and, 399–400

disabling FETCH button after, 384–385

promises used for, 381–384

fetchPromise object, 381

files

finding, 21

saving, 20

fillRect function, 418

fillText method, 454

filter method, 377, 402

finally function, 385, 387, 403

findContactPos function, 283, 284, 285, 286, 287

findContacts function, 284

finding

files in Visual Studio Code, 21

info in contacts app, 283–285

Super Search for, 310–315

findStartsWithDataPos function, 313, 314

firewalls, 391

fixed-width layouts, 268–269

floating-point numbers, 114–116

equality and, 153

errors related to, 114–115

real numbers and, 114

floor function, 117, 118, 129, 141

focus, loss of, 435–436

fonts

families of, 68, 69, 87

monospaced vs. proportional, 36

selecting for text, 68–69, 70

serif vs. sans-serif, 68, 70

size specification, 70–71

for loop, 191–195

code analysis, 192–194

elements of, 191, 203

findContacts function and, 284

for-of loop, 195–196, 204, 221, 259

friction, game, 457–458, 459

functions, 43, 61

anonymous, 374

arguments given to, 214–216

arrow, 374–375

calling, 208, 209, 210–211

code analysis of, 209–212

defining, 208, 209–210, 213

designing with, 228

explanation of, 43, 208–213

giving information to, 213

helper, 280–281

local variables in, 233–236

methods distinguished from, 61, 341, 365

multiple parameters in, 218

naming, 213, 239

side effects of, 136, 137

values returned from, 222–226

G

game engines, 465

gameEnd method, 464

gameplay controls, 429–436

event listener, 429–430

keyboard events, 430–435

lost focus and, 435–436

window events, 429–430

gameReset function, 442

gameRun method, 463

gameRunning property, 463, 464, 468

games

animating images for, 427–429

artificial intelligence in, 456–457

attract mode for, 468

building your own, 465

classes for, 438, 440–441

code analysis for, 438, 440–441

collision detection for, 455

controls for playing, 429–436

drawing images for, 419–421

end detection for, 464

event listener for, 429–430

fixing problems in, 456

friction in, 458, 459

image loading promise for, 421–425

including instructions with, 461

keyboard events for, 430–435

losing focus in, 435–436

making playable, 465

objects for, 436–460

party, 137–140

physics used in, 457–458, 459

running, 441, 463–464

scores added to, 453–454, 464

sound added to, 140, 452–453

sprites in, 436–438, 443–452, 456–460

start screen for, 461–462, 463

gameStart method, 441, 442, 463

gameUpdate function, 428, 433–435, 442–443, 463

“get” requests, 29

getAttribute method, 185, 186–187

getDescription method, 349, 350–352

getElementByID method, 45–46, 47, 55

getElementValue function, 281

getHighest function, 250

getHours method, 72

getHTML method, 358–359

getImages function, 423, 424

getItem method, 294, 295

getLargestStockRef method, 353, 354

getLowest function, 250

getNumberFromElement function, 226, 229, 230–231, 260, 263

getRandomColor function, 418

getRandomInt method, 353, 417

getTestItems method, 353, 354

getTotal function, 250

Gimp program, 419

Git program, 13–14

installing, 14

repositories in, 17

GitHub service, xviii, 16

private work on, 24

repositories on, 17

global variables, 134–136, 142, 143, 235, 417

H

headers

function, 227, 237

response, 404

heading tags, 35

helper functions, 280–281

hierarchy of classes, 345, 347–348

High and Low game, 139

highlighting elements, 269

host element, 29, 393

hover selector, 87

href attribute, 41

HTML (Hypertext Markup Language), 12, 27–50

audio element, 55, 56

badly formatted, 37–38

button creation, 42–44

canvas element, 410–425, 468

comments added in, 38, 133

creating, 359–360

data attributes in, 184–188

document formatting, 41

heading creation, 35

how it works, 29–32

images added in, 38–40

input element, 44–45, 244

JavaScript and, 45–48, 58, 199–201

links used in, 41–42

origins and development of, 28

paragraph layout, 34

prototype example, 277–278

routing in, 393–394

schema for building, 305–308, 358–359

styles added to, 64–85

symbol display, 32–33

text display, 49–50

validator site, 38

web servers and, 396

<html> tag, 41

HTTP and HTTPS protocols, 28, 29

Node.js platform and, 389–390, 404

server requests vs. responses, 406

stateless description of, 407

I

i variable, 233, 236

ice cream sales program, 242–269

arrays used in, 246–248, 265–268

collections of data in, 242–246

detecting invalid values in, 251–252

finding highest/lowest sales in, 249–251

fixed-width layouts for, 268–269

highlighting elements in, 269

user interface for, 252–264

id attribute, 44, 58, 90

identifiers, 108–109

identity operator, 152, 173, 174

if construction, 158–161, 173, 174

blocks of statements in, 160–161

else keyword added to, 159–160, 174

Math.random function used in, 172

images

adding to web pages, 38–40

alternative text for, 39

animating, 427–429

drawing on a canvas, 419–425

example of moving, 428–429

file types for, 419–420

loading and drawing, 420–421

program for displaying, 57

promises for loading, 421–425

<img> tag, 38–40, 57, 419

index values, 271–272

indexer or subscript, 246

infinity value, 11, 148

information vs. data, 103

inheritance, 343–344, 345–347, 364

innerText property, 51, 243

<input> tag, 44–45, 244, 278, 318

input paragraphs, 254–257, 258

input validation, 175

installing

Git program, 14

Node.js program, 387–389

Visual Studio Code program, 15–16

Internet of Things (IoT), 97

Internet vs. World Wide Web, 59

isNaN function, 230

J

Java programming language, 5, 346

JavaScript

Boolean thinking in, 146–157

data processing in, 99, 100, 104

evaluating expressions with, 100–102

examples of talking to, 10–12

exceptions thrown by, 324, 364–365

functions and statements in, 43

HTML and, 45–50, 58, 199–201

identifiers in, 108–109

local storage, 292–295

origins and intention of, 5

programming languages and, 4–5, 6, 23

prototype example, 279–280

tools for working with, 13

variables in, 46, 58, 105–108

web browsers and, 6

JPEG file format, 419

JSON (JavaScript Object Notation), 295–299

adding type info to, 355–356

class hierarchy and, 355

code analysis of using, 299

encoding object data with, 295–298, 317

example of working with, 296–297

exceptions thrown by, 299, 324, 325–326

fetched data and, 382

validator web page, 327

JSONparse method, 356, 357

K

keyboard events, 430–435

code analysis, 430–431, 432–433

gameUpdate function, 433–435

object position control, 431, 432–433

keydown event, 429–430, 433, 463

keyup event, 431, 433

keywords, 24

L

label element, 244, 255

lambda functions, 375

layouts

fixed-width, 268–269

paragraph, 34

styles vs., 81

length property, 271

let keyword, 193, 205, 235–236, 238

letDemo function, 236

<li> element, 164, 188

lineTo method, 412

<link> element, 81

links, HTML, 41–42, 81

listen method, 390, 392, 404

lists

creating, 369–370

investigating, 189–190

ordered, 164

unordered, 188

loadDataStore function, 331–332

local storage, 292–295, 317

explanation of, 292–293

investigating the use of, 293–295

web browsers and, 293, 318

local variables, 135, 233–236

let keyword for, 235–236

scope of, 234–235

localhost address, 391

LocalStorage object, 293

logic errors, 109–110

logical operators, 154–157

lookup tables, 265–266

loops

for, 191–195

for-of, 195–196

while, 201–202

M

makeElement function, 307–308, 315

makeInputPar function, 254, 255, 256

management

error, 335

local storage, 293

style, 86

manifest configuration file, 401

map method, 379, 402

margins, text, 77–79, 88

markup languages, 29–30

Math class, 354

Math.random function, 172

max attribute, 230–231, 254

measureText method, 462

menuInput style, 229

menuInputError style, 229

menuLabel style, 269

message variable, 46

methods, 45–46

adding to classes, 348–349

functions distinguished from, 61, 341, 365

overriding in subclasses, 350–352

Microsoft Paint program, 419

Microsoft Press resources, xix

min attribute, 230–231, 254

mobile devices, xviii

modules, 389

monospaced font, 36

mouse rollover

color highlighting on, 66–67

rollover style and, 87

moveTo method, 412

moving images, 428–429

multiplication table program, 196–203

code analysis, 199–201

deleting elements from, 201–202

displaying scores in, 270

ideas to investigate for, 202–203

myCanvas variable, 411

myContext variable, 412

N

names

function, 213, 239

sorting array of, 373

NaN value, 11, 125, 141, 142, 148, 230, 231

Nerves of Steel game, 138

nesting, bad, 37–38

Netscape Communications Corporation, 5

networks

JSON data received from, 383

text received from, 384

new keyword, 72, 75, 339, 364

Node.js program, 387–401, 403–404

HTTP module, 389–390, 404

installing and testing, 387–388

multiple path use, 394–396

node package manager, 401, 404

purpose and limitations, 389

server deployment, 401

web server creation, 389–400

node package manager (npm), 401, 404

notation

dot vs. bracket, 300, 317

JavaScript Object, 295–299

null value, 299

Number function, 124, 125, 141, 142, 213

numbers

combining text and, 120–121

converting text into, 122–123

entering invalid, 125–126

floating-point, 114–116

random, 116–118, 137–139, 222–226

reading, 259–260

real, 112–113, 114, 141

whole, 112–113, 141

numeric operators, 111

O

obfuscator programs, 23–24

object-oriented design

explanation of, 341–342

inheritance mechanism in, 343–344

objects, 288, 316–317

abstraction using, 344–345

class creation and, 339–340

constructors and, 340–341

creating, 288–291, 339

empty, 288, 300, 316

example of using, 291–292

JSON for encoding data in, 295–298

polymorphism and, 350

position control for, 431

promise, 381–382, 424, 426

properties of, 50–51, 300, 316–317

references to, 49, 60, 290–291, 299, 317

schema for building, 308

storing data in, 288, 292–293, 295

<ol> element, 164

onclick attribute, 43, 225, 236

onerror event, 421

oninput function, 313–314, 315

onload event, 74, 77, 253, 421, 441

onmouseout event, 67

onmouseover event, 66, 86

openPage function, 361

OpenWeather service, 379, 398

operands, 100, 110, 141, 142

operators, 100, 110, 141, 142

comparison, 150–152

logical, 154–157

numeric, 111

ordered lists, 164

overlapping elements, 37

overriding methods, 350–352

P

<p> tag, 34

paragraphs

creating input, 254–257, 258

laying out text in, 34

parameters

arguments and, 216–217

functions with multiple, 218

as values, 217

parse method

JSON strings and, 297, 299, 317, 325–326

URL strings and, 395–396, 397

party games, 137–140

paths

defining and drawing, 412

in URL structure, 29, 393

using multiple, 394–396

Petzold, Charles, 104

Phasor game engine, 465

physics of games, 457–458, 459

pixels, 39, 78, 88, 90

pizza calculator, 127–129

playback control, 56, 140

player sprite, 445–446

plus (+) operator, 111, 119, 120

PNG file format, 419

polymorphism, 350

pos variable, 284, 285

<pre> tag, 35–36

preformatted text, 35–36, 59

Preview image editor, 419

print function, 12

problem solving, 311

programming languages, 4–5, 6

compiled, 23

determining the “best,” 5

scripting, 23, 102

programs

audio added to, 55

bugs vs. faults in, 67

comments added to, 131–133, 141

data processing in, 98–99

error handling for, 227–232

good specifications for, 134

interpreting, 102

user interface for, 162, 163–165

variables in, 105–108

See also applications

Promise.all method, 422–423, 426

promises, 381–387, 405–406

controller function for, 422

explanation of, 381–382, 386, 403, 405

finally function in, 385

handling errors in, 384

image loading, 421–425

importance of understanding, 427

investigating, 385–387

JSON delivery process, 382

managing multiple, 422–423, 426

simplifying with anonymous functions, 383

text delivery process, 384

waiting for results of, 424–425, 426

properties

attributes vs., 60

explanation of, 300

object, 50–51, 300, 316–317

property accessors, 300–304

explanation of, 300, 305, 319

investigation of, 301–303

property identifiers, 303

propertyName variable, 304

proportional fonts, 36

prototypes

HTML, 277–278

JavaScript, 279–280

style sheet, 278–279

pseudocode, 249

px unit, 78, 88, 90

Q

query strings, 397–398, 404, 406

quote character, double (") and single ('), 119, 141, 143

R

random artwork, 417–418

random function, 116, 117, 118

random numbers, 116–118, 137–139, 222–226, 469

Raspberry Pi computers, xviii

real numbers

floating-point numbers and, 114–116

whole numbers vs., 112–113, 141, 142

recursion, 212

reduce method, 378, 402

refDemo variable, 290–291

references

as arguments, 219–220

array of, 372

game, 440

object, 49, 60, 290–291, 299, 317

property accessors and, 319

stored in JSON strings, 299

relational operators, 152

removeChild method, 201, 204

removeItem function, 295

repeating code, 343

repositories, 17–19

requestAnimationFrame method, 427, 429

requests, HTTP, 406

require function, 389, 401, 403

resetFind function, 314

resource information, xix

responses

contents of, 404

JavaScript commands and, 10–12

requests vs., 406

result variable, 125

return keyword, 222

rgb function, 418

ride selector program, 161–172

code added to, 165–168

example of modifying, 178–181

fixing faults in, 181–183

switch construction in, 168–170, 171

user interface for, 162, 163–165

rollover style, 87

running games, 463–464

S

salesItems element, 259–260

sans-serif fonts, 68, 70

saving files, 20

scaffolding, 401

schemas, 304–308

data storage created from, 309

designing for applications, 304–305

HTML built from, 305–308, 358–359

objects built from, 308

scope of variables, 234–235

scores

adding to games, 453–454, 464

displaying in programs, 270

<script> element, 43, 58

scripting languages, 23, 102

searching. See finding

selectors

color highlighting using, 86–87

style sheets using, 80

semicolon (;) character, 76

sendResponse function, 395

serif fonts, 68, 70

servers

code analysis of using, 390–392

deploying Node.js, 401

process of building, 396

See also web servers

service function, 404

setAttribute method, 187

setInterval function, 74, 77, 88, 427

setItem method, 294, 295

setTimeout function, 52, 54, 57, 58

setup element, for loop, 191

shadow effect, 164–165, 462

side effects, 136, 137

single quote (') character, 119, 141, 143

slide shows, 57

software. See programs

solving problems, 311

sort method, 371–373, 374

sorting data, 371–373, 376–377, 402

sound

adding, 55, 140, 452–453

playback control, 56, 140

source code, 13

source code highlighting, 24

source code management (SCM) software, 14

Source Control dialog, 18

<span> element, 84–85, 88, 90

specifications, 134

spelling errors, 110

sprites, 436–438, 443–452, 456–460

AI added to, 456–457

cheese, 443–444

cracker, 447–452

friction added to, 458

killer tomato, 456–458

physics of, 457–458, 459

player, 445–446

superclass for, 438

timed, 459–460

square brackets [ ], 189, 288, 296, 319

src attribute, 39, 55, 57, 420

start and end tags, 32

start screen for games, 461–462, 463

startsWith method, 312, 314, 317

statements

alert, 43

assignment, 105

blocks of, 160–161, 193

for loop, 191

static class members, 352–355, 357, 364

static keyword, 353, 354

status code, 404

Step control, 262–263

stockItemCompare function, 372–373

storage

arrays used for, 246–248, 281–283

class hierarchy and, 355

examples of breaking, 333–334

local, 292–295, 317

schema produced for, 309

storeContact function, 283, 292

storeData function, 308

stories, user, 336

stringify method, 296, 297, 317, 325, 329–330

stringOrderCompare function, 373

strings of text. See text

stroke method, 412–413

<strong> tag, 32

<style> tag, 80

style sheets

adding to documents, 80, 88

exploring the use of, 83

file created for, 80–81, 88

prototype example, 278–279

See also CSS

styles, 64–91

cascading, 85–86, 88

classes of, 82, 84

color, 64–67

conflicting, 89

explanation of, 64

font, 68–71

layouts vs., 81

managing, 86

margin, 77–79

menu label, 269

overriding, 86

selectors for, 80, 87

style sheet for, 80–81

text alignment, 71

subclasses

class hierarchy and, 345

extending classes and, 346

inheritance mechanism and, 343–344

overriding methods in, 350–352, 364

template for, 438

subscript, 246, 271

super keyword, 348, 352, 364

Super Search feature, 310–315

code analysis of, 314–315

problem solving for, 311

solutions for creating, 312–314

superclasses

class hierarchy and, 345

game sprites and, 438

inheritance mechanism and, 343–344

super keyword and, 348, 352

switch construction, 168–171

explanation of using, 168–170

missing breaks in, 171

path for controlling, 394

symbols, HTML display of, 32–33, 58

synchronized actions, 380

T

TCP/IP protocol, 29

temperature conversion program, 130–131

template, subclass, 438

test element, for loop, 191

testing

error, 110, 126

Node.js, 388

text

aligning, 71, 88

alternative, 39

arrays of, 265

combining numbers and, 120–121

converting into numbers, 122–123

delimiters for, 119

displaying, 49–50, 462

emphasizing in HTML, 30

encoding with JSON, 295–299

escape sequences for, 120

fonts selected for, 68–71

getting from networks, 384

heading creation, 35

indicating with quotes, 10

margins around, 77–79

paragraph layout, 34

preformatted, 35–36, 59

as property accessors, 300–304

shadow effect, 164–165, 462

styling, 64, 71

text method, 384

textarea element, 278, 318

textContent property, 49, 50–51

Theme Park Ride Selector. See ride selector program

then method, 381, 382, 384, 386, 403, 405–406

this keyword, 340, 341, 364, 365, 376, 440, 442–443

threads, 426

throw statement, 329

ticking clock program, 72–77

code analysis, 75

creating, 74–75

time display, 72–73

timed sprites, 459–460

timeString variable, 73

Tiny Contacts application. See contacts app

toFixed method, 130

Torvalds, Linus, 14, 24

total variable, 135, 136

totalizer program, 133–137

trim function, 314, 317

true keyword, 146, 147–148

try block, 326, 327, 328

try-catch construction, 326, 327, 328, 363, 386–387

Twitter information, xix

two-dimensional arrays, 272

type attribute, 44

type property, 356

U

<ul> element, 164

undefined value, 106, 107, 141, 142

unordered lists, 188

update element, for loop, 191

update method, 434, 438, 451, 453, 460, 464

URLs (uniform resource locators)

parse method and, 395–396, 397

query strings added to, 397–398, 406

structure of, 28–29, 59, 393

user interface

designing for customers, 162, 252–254

examples of building, 163–165, 252–264, 357–359

improving for contacts app, 309–316

input paragraph creation, 254–257

users

reading input from, 44–45

receiving ideas from, 310, 316

written stories for, 336

V

validator site, 38, 327

value attribute, 44

values

Boolean, 146–149, 173, 174

floating-point, 114–115

functions returning, 222–226

NaN, 11, 125, 141, 142, 148, 230, 231

parameters as, 217

query, 397

undefined, 106, 107, 141, 142

var keyword, 48, 72, 75–76, 205, 235, 238

variables

control, 191

creating, 48, 72, 75–76, 193, 236, 239

function of, 46, 105, 141

global, 134–136, 142, 143, 235, 417

local, 135, 233–236

scope of, 234–235

working with, 106–108

video walkthroughs, xviii

Visual Studio Code program, 13, 25

App Service Extension, 401

cloning repositories with, 18–19

color styles added in, 65

editing files with, 19, 20–22

finding files in, 21

font selector in, 69

installing, 15–16

keywords in, 24

Node.js test in, 388

server run in, 390–391

Visual Studio suite, 25

W

weather application, 379–385

web browsers

badly formatted HTML in, 37–38

JavaScript used in, 6

local storage managed by, 293, 318

web pages, 28

building from code, 196–201

fetching with URLs, 28–29

ideas for creating, 57

images added to, 38–40

viewing code on, 6–9, 273

web servers

creating with Node.js, 389–400

deploying Node.js, 401

JavaScript and, 23

web services, 398, 402

websites, 28

while loop, 201–202, 204

whole numbers, 112–113, 141, 142

window events, 429–430

window object, 427, 429

World Wide Web (WWW)

HTML and, 28

Internet vs., 59

World Wide Web Consortium (W3C), 28

write method, 392

Code Snippets

Many titles include programming code or configuration examples. To optimize the presentation of these elements, view the eBook in single-column, landscape mode and adjust the font size to the smallest setting. In addition to presenting code and configurations in the reflowable text format, we have included images of the code that mimic the presentation found in the print book; therefore, where the reflowable format may compromise the presentation of the code listing, you will see a “Click here to view code image” link. Click the link to view the print-fidelity code image. To return to the previous page viewed, click the Back button on your device or app.