Project Falcon
Dynamic Front ends!
JavaScript is a dynamic, weakly typed, prototype-based programming language. But JavaScript is mostly used on the frontend or client side of web applications. Though now, JavaScript is able to be used as a full stack tool for developing robust web applications thanks to Node.js. We will only be going through using JavaScript on the frontend to add interactivity with our end user.
We can include JavaScript in our page very similarly to how we include CSS. Like CSS there are 3 options (and two of them are not advised).
We can include JavaScript right inside of our HTML elements. (Your separation-of-concerns-sense should be tingling right now):
<h1 onclick="this.style.color = 'pink';">My Title</h1>
Which gives you:

You can also write JavaScript directly inside your HTML by enclosing it in <script> tags. Like this:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>JS Example</title> </head> <body> <h1 onclick="this.style.color = `pink`">My Title</h1> <h2>My Subheading</h2> <script type="text/JavaScript"> document.getElementsByTagName('h2')[0].onclick = function() { document.getElementsByTagName('h2')[0].style.fontSize = `30px`; }; </script> </body> </html>
Which yields:

Finally, similar to CSS, you can link JS code from an external file. This is ideal because it keeps your code organized and concerns separated. You connect the file to your HTML with the <script> tag like so:
<!-- index.html --> <script src="./js/app.js"></script>
// app.js document.getElementsByTagName('h3')[0].onclick = function () { this.style.backgroundColor = `orange`; };
Which gives you:

JavaScript allows you to send and receive messages from your user in a number of ways. The first ones we're going to talk about are boxes. There are three types of boxes:
Let's explore them in more detail.
Alert boxes allow you to send a message that your user can read when an action is performed. By adding a button we can see how this works:
<button type="button" name="button" id="alert"> Alert Box </button>
And inside of our JS file:
const alertButton = document.getElementById('alert'); alertButton.onclick = function () { alert('Here is our alert box'); };
Which then performs like this:

Confirm boxes actually return a boolean value to you. This way you can interact with your user and get some kind of feedback from them. When your user clicks ok in the confirm box, you get a true value. When they click cancel, you get a false value:
<button type="button" name="button" id="confirm">Confirm Box</button> <output name="result" id="confirmResponse"></output>
And inside of our JS file:
const confirmButton = document.getElementById('confirm'); confirmButton.addEventListener('click', function () { const userResponse = confirm('I can haz cheeseburger?'); const displayContainer = document.getElementById('confirmResponse'); const displayMessage = ''; if (userResponse) { displayMessage += 'Thank you! I love cheeseburger'; } else { displayMessage += '😢'; } displayContainer.innerText = displayMessage; });
Which then performs like this:

Prompt works very similar to to confirm. It accepts input from your user as well. This time the value is a string. So you can get specific information from your user and use it however you want.
<button type="button" name="button" id="prompt">Prompt Box</button> <output name="result" id="promptResponse"></output>
And inside of our JS file:
var promptButton = document.getElementById('prompt'); promptButton.onclick = function () { const userResponse = prompt('What is your name?'); const displayContainer = document.getElementById('promptResponse'); displayContainer.innerText = `Hey, ${userResponse}`; };
Let's see what it does when we give it a value and what we get when we hit cancel:

We can print to our console with JS the same way we can with Java. The only thing that's different is the command to execute this behavior.
In JS that command is console.log(). There is also console.error() and console.dir. They are for more specific tasks but have generally the same behavior. Let's see them in action:

There are now three keywords you may use inside of JS to declare a variable. Two of them are new, one of them you are very used to using. The reason new variable declaration words have been created in the first place is to fix a big problem that JS has inherently had with polluting the global scope. The two new keywords have block scoping. This means they inherently don't belong to the global scope. Let's explore that.
varWe've seen var as the standard variable declaration keyword.
var myNum = 42; var myString = 'This is a string value'; var myBoolean = true;
This keyword will still work but it is advised that you use either of the new keywords instead.
letThe let keyword has block scoping which allows it to be declared outside of a function but still not be considered part of the global scope. Let's see how this actually affects our code.
varSo we have 5 buttons on our page that should be logging out the looped value assigned to it.
var buttons = document.getElementsByTagName('button'); for (i = 0; i < buttons.length; i++) { buttons[i].addEventListener('click', function () { alert('Button ' + i + ' was clicked!'); }); }
Notice that we're getting the alert value of 5 no matter which button we press.
letSo we have 5 buttons on our page that should be logging out the looped value assigned to it.
let buttons = document.getElementsByTagName('button'); for (let i = 0; i < buttons.length; i++) { buttons[i].addEventListener('click', function () { alert('Button ' + i + ' was clicked!'); }); }
Now we're getting the expected result each time because the i value is block scoped to the for loop during each iteration.
constconst is a powerful new keyword that actually gives us constant values in JS. This way they can't be over written. For example:
var name = 'Donny'; if (name === 'Donny') { name = 'Alan'; // Changes the value }
But with const:
const name = 'Donny'; if (name === 'Donny') { name = 'Alan'; // Causes an error }
constSo if we can't change the value of a const variable, how are we supposed to work with things like arrays and objects? There inlies the beauty of this new keyword. We are still allowed to mutate arrays and objects, we just can't redeclare them.
// This will throw an error const myArray = []; myArray = 'This is an array'; // This will add values to your array const myArray = []; myArray.push([1, 2, 3]);
constAnd we can see the same behavior with objects:
// Error const myObj = {}; myObj = 'This is an object.'; // Adds a name property to my object const myObj = {}; myObj.name = 'Donny';
Strings in JS operate just like they do in most other languages. They're just collections of characters.
Concatenating is the same here as well (notice how similarly programming languages behave?). In fact, we use the same concatenation operator in JS as in Java:
const myName = 'Instructor'; console.log('Hey, ' + myName + "! How's it going?");
This would print out Hey, Instructor! How's it going? to the console.
We have a new way to declare strings too and it has way more functionality than we had previously. Instead of using single or double quotation marks, you can now declare a string with back-ticks `` (located to the left of the <1> key).
The first advantage of `` over quotes is multiline strings. With quotes, these are declared like so:
const myNewElement = '<ul>' + '<li>value 1</li>' + '<li>value 2</li>' + '<li>value 3</li>' + '</ul>';
With `` we can make this way easier:
const myNewElement = ` <ul> <li>value 1</li> <li>value 2</li> <li>value 3</li> </ul> `;
This way we can essentially write HTML right into our JS!
Interpolation is another super useful advantage to multiline strings. Let's look at how we are used to including variables in our strings.
const name = 'Donny'; console.log('Hey! My name is' + name + '. How goes it?');
We can simplify this way more with interpolation. No more worrying about concatenation operators!
const name = `Donny`; console.log(`Hey! My name is ${name}. How goes it?`);
More of the same here. JS has the same comparison operators as Java. It adds two new ones though and that's what we're going to focus on.
==!=><>=<====!==These last two have more specificity than == and !=. With the less specific operators, if two objects have similar values, they are considered equal. Similarly, the more specific versions will compare the types and values i.e.
5 == '5'; // true 5 === '5'; // false
These are the same as Java.
&&||!+-/*%++--You can comment things out in JS also. You can use // for inline commenting and /* */ for commenting blocks of code.
const name = 'Instructor'; // This is a name /* Here is a bunch of stuff that I want to comment out because it isn't actually relevant to our code. */
Arrays in JS are way more useful than the arrays we're used to. They're mutable, which means you can alter them. There are two ways to declare an Array:
const myFavoriteFruits = ['bananas', 'oranges', 'papaya', 'mango', 'pineapple']; const myEmptyArray = new Array(5);
When we print these to the console we get:

Similar to what we're used to, these arrays are also zero-based and have a built in length property.
We can add and remove items to the end of our arrays using the .push() and .pop() methods.
// This removes 'pineapple' from the // array and stores it in the variable // pineapple. const pineapple = myFavoriteFruits.pop(); // This adds the value 'watermelon' // to the end of our array. // ['bananas', 'oranges', 'papaya', 'mango', 'watermelon'] myFavoriteFruits.push('watermelon');
The splice method allows you to remove any number of items from your array at any given location. Splice accepts two parameters .splice(index, number of items to remove). So for example:
// Current value of myFavoriteFruits // ['bananas', 'oranges', 'papaya', 'mango', 'watermelon'] // // This will store the array ['papaya', 'mango'] const myMostFavorite = myFavoriteFruits.splice(2, 2); // It also makes our array have the value of // ['bananas', 'oranges', 'watermelon']
Now you're wondering, if I can add and remove to the end of my array, what if I want to add to the front? We use the methods .shift() and .unshift().
// Makes our array have the value of // ['blueberries', 'bananas', 'oranges', 'watermelon'] myFavoriteFruits.unshift('blueberries'); // This variable gets passed the value 'blueberries' const kingOfBerries = myFavoriteFruits.shift();
There are a few different ways to add values to our array. We can declare our array with values already inside:
// This array has five values. Notice how // we can mix value types in JS arrays const numbers = [1.0, 2, 'three', 4, 'five'];
We can also give values to specific indices in arrays:
const names = new Array(3); // This changes the value of the second // item from null to 'Alan' names[1] = 'Alan'; // This creates a key of 'Brian' // and gives it the value 'Brian' // But this is bad... don't do this... names['Brian'] = 'Brian';
We have objects in JS the same as Java. They behave in a similar fashion
Functions and variables are the anonymous versions of methods and properties. Once a variable is placed inside of an object, it is a property of that object. The same goes for functions and methods. Let's look at how to declare an object in JS and give it some properties and methods.
const Car = { color: 'green', hornSound: 'BEEEEP!', numOfWheels: 4, honk: function () { console.log(this.hornSound); }, }; // We can also add values like this Car.engine = 'V8';
We can use objects in JS to encapsulate our applications. We do this by making everything part of an object and containing all of our properties and methods inside of the object. This way we can avoid name collision inside of our global scope. This allows us to have only one global object, our application, which should be named uniquely so that no other plugins or libraries will use the same names as you.
const MyApp = { users: [], userCount: users.length, addAUser() { // logic to add a user }, };
Now MyApp is the only thing that we are adding to our global scope, everything else is local to our application and can't be accessed directly by our browser or any other JavaScript frameworks or libraries that may be in our document.
We can access current times and dates on the user's machine with JavaScript. Make sure to note that times are based on the settings on the user's machine so we can't be sure that our intended time or date will display. We reference a new Date object like so:
const date = new Date(); // This method shows the number of milliseconds // that have passed since 1 January 1970 00:00:00 UTC. date.getTime(); // This value gets the current year date.getFullYear();
There are many useful methods on the Date object. Read about them here. You can read about why we're getting milliseconds since 1 January 1970 here.
JavaScript has plenty of useful built-in methods for you to use. Two of the most frequently used are setInterval(time in milliseconds, function to execute) and setTimeout(time in milliseconds, function to execute). These are used to delay operations from happening until a specified time. In the case of setInterval(), we are setting up intervals for operations to be executed multiple times in increments set by the developer.
Let's see how they work:
const i = 0; // This will call setInterval() and // execute the anonymous function // that we're passing it. const interval = setInterval(function () { i++; console.log(i); if (i === 10) { clearInterval(interval); } }, 1000); // This will log to the console // after 11 seconds. setTimeout(function () { console.log('This took 11 seconds'); }, 11000);
But, what is that function doing?
Probably the biggest tool we have in front end JS is the DOM API. This is what allows us to dynamically populate our pages with elements based on data being updated. Let's look at some code to see how this works. Let's look at referencing DOM elements first:
<!-- index.html --> <body> <h1 id="title">Here's my title</h1> </body>
// app.js // This tells our browser that we are // referencing this specific element // and sets it to a variable. const title = document.getElementById('title');
Let's now look at what we can do with the element we've grabbed:
const title = document.getElementById('title'); // This will set the text inside of our #title to a new value title.innerText = 'This is dynamically set text.'; // But what if we want to add HTML element? title.innerHTML = 'This is <span>dynamically</span> set text!';
This allows you to put actual HTML elements into your element via a string. We can now manipulate this span with CSS!
We can also work with attributes on the element (i.e. things like href or type).
// This gives us a variable with the value // of the ID attribute. const titleId = title.getAttribute('id');
We can also see if an element has an attribute and, if so, examine what its value is.
// This returns us a boolean value // of false because our 'h1' element // doesn't have an 'href' value title.hasAttribute('href');
The same way we can manipulate elements, we can remove them:
// The remove method is built in to the DOM API // and deletes an element from our document for us. title.remove();
So we find ourselves selecting elements in a very clumsy way. There seems to be a different way to find each element in the DOM API. Why not one way? BECAUSE THERE ARE TWO! .querySelector('thing') and .querySelectorAll('things').
// This selects the first element of // its kind in the document. document.querySelector('h1'); // This selects a group of things // that have the parameter in common. document.querySelectorAll('.content');
This way we can select elements more dynamically.
Event handlers are the way we deal with interactivity. So, for example, if we want to change the way our heading is sized when our user clicks on it, we can!
const title = document.querySelector('#title'); // This is going to make your 'h1' tag(s) // be '50px' when you click it title.addEventListener('click', function () { title.style.fontSize = '50px'; });
We can also add event listeners like this:
const title = document.querySelector('#title'); title.onclick = function () { title.style.fontSize = '50px'; };
Event Bubbling and Event Delegation are processes by which your interaction with the DOM affects all elements affected by a given interaction. This is to say that any action you perform to an element on a page is also performed on any parent element(s) of said element. For example, say we have the following html:
<body> <div class="container"> <header> <h1>Title</h1> <nav> <ul> <li><a href="#">Nav link</a></li> </ul> </nav> </header> </div> </body>
We now have the ability to click the a element. But, when we click that element, we are clicking all containing elements. So we're also clicking li, ul, nav, header, div.container, and body.
Conversely, behavior can be observed from a parent container and delegate behavior to a child element using event.target in the DOM API. Like so:
<body> <h1 class="someClass">Title!!!</h1> <p>I don't have class :,(</p> </body>
const body = document.body; body.addEventListener('click', function () { if (event.target.classList.contains('someClass')) { console.log("you pressed the thing that was a class list of 'someClass'"); } });
In JS we have two ways to declare a function, function declaration and function expression. Function declarations look like this:
function myFunc() { // Do something with stuff }
Where function expressions look like this:
const myNewFunc = function () { // Do something new with new stuff };
We now have arrow functions. Let's take a look!
Let's refactor a function with no arguments and make it an arrow function:
function logToTheConsole() { console.log(`Print me to the console!`); }
Let's do the same with functions that have one argument:
function numberSquared(x) { return x * x; }
Finally, let's see this in action with many arguements:
function addTwoNumbers(x, y) { return x + y; }
Look how much smaller our code base can become
const logToTheConsole = () => console.log(`Print me to the console!`); const numberSquared = (x) => x * x; const addTwoNumbers = (x, y) => x + y;
We can provide default parameters for our functions in ES2015+ the same way we can with ES5 style JS. But as with most things in ES2015, it's far easier. For example:
// ES5 syntax function add(a, b) { if (a === undefined) a = 42; if (b === undefined) b = 86; return a + b; } // ES2015 syntax const add = (a = 42, b = 86) => a + b;
That anonymous function that we pass to setInterval is called a callback. Callbacks are used to execute specific behavior with a value that has been passed to it. Let's explore:
const colors = ['red', 'green', 'blue', 'yellow']; function listAllColors(array, callback) { list = ''; for (let i = 0; i < array.length; i++) { list += array[i]; if (i < array.length - 1) { list += ', '; } } callback(list); } listAllColors(colors, function (listOfColors) { console.log(listOfColors); });
This prints the concatenated array to the console:

ES2015 gives us a great tool for declaring variables called destructuring. This is a way to declare individual variables from and object. Since Arrays are actually objects in JS, this applies to them too. Let's see it in action:
// ES5 syntax const list = [1, 2, 3]; const a = list[0]; const b = list[1]; const c = list[2]; console.log(a + b + c); // prints 6 // ES2015 syntax const list = [1, 2, 3]; const [a, b, c] = list; console.log(a + b + c); // also prints 6
The same works for objects. This is great if you just want to assign a few values from an object to single, local variables.
// ES5 syntax const obj = { name: 'Donny', age: 31, favColor: 'green' }; const name = obj.name; const favColor = obj.favColor; console.log(name + 's favorite color is ' + favColor); // ES2015 syntax const { name, favColor } = { name: 'Donny', age: 31, favColor: 'green' }; console.log(`${name}s favorite color is ${favColor}`);
Now it's time for...
There's plenty more to understand about JavaScript. For this project, pull this JS challenge exercise here and answer these questions.