Setup
Before starting this prelab, ensure that you have:
- Accept this Github Classroom assignment and clone this repo that contains stencil code for this prelab.
 - We have 2 tasks listed at the bottom of this page that you'll have to complete and handin.
 
Introduction
The Language of the Internet
JavaScript, also known as ECMAScript, is one of the world's most popular and misunderstood programming languages. This prelab introduces you to some of the tools you'll need to begin programming in JavaScript!
Warning: This prelab is a bit on the longer side, but incredibly important to complete especially if you haven’t used JavaScript before. We're going to be giving you a lot of sample code in this lab, but we recommend typing it in instead of copy/pasting; it'll help you learn the syntax.
What you'll get to know
- JavaScript and its ~fun quirks~
 - The Document Object Model (DOM)
 - How to dynamically alter a page through a hands on experience
 
What is JavaScript?
From the Mozilla Developer Network (a great site for help with JS):
JavaScript (JS) is a lightweight interpreted or JIT-compiled programming language with first-class functions. While it is most well-known as the scripting language for Web pages, many non-browser environments also use it...
JavaScript is basically the only language you can use in the browser to control the web page (e.g. make pop-ups, create an image slider, build infinite scroll). To control the web page, you use the DOM API, which is a platform and language-neutral interface that will allow programs and scripts to dynamically access and update the content, structure and style of documents.
Using the console
We're going to learn about JavaScript syntax straight from the browser. Modern browsers have built in developer tools that allow us to look at the code of any website. To do this:
- 
                        Create an 
index.htmlfile (with a general HTML template) and drag the file into your browser to open it, or useindex.htmlfile provided in the stencil for this prelab. We recommend using Google Chrome, but you can also use FireFox or Safari if you prefer. - 
                        In order to include JavaScript in your HTML page you need to use a script tag,
                        
<script>...</script>. You can type any Javascript code inside the tag and it will be executed while the page is loading. Alternatively, you can write JavaScript in a separate file and include it externally with<script src="path/to/index.js"></script>. In most cases, just as you should avoid using inline CSS styling, it is also highly advised to use external imports if possible by writing all your JavaScript in a separate file. For the purposes of this prelab it’s okay to follow along by including all your JavaScript in a script tag, but we also encourage you to play around with using imports. - Right click anywhere on the page, and click on "inspect". This should pull up the developer tools. You should see all of the HTML code of this page. Moving your mouse over the different tags will show you its corresponding elements on the page. Right now, we don't have anything in our webpage, but once elements get added, they will start to show up.
 - 
                        Notice in the developer tools there is another tab called "console."
                        
- In Chrome, this is the second tab of the DevTools. (How to open Chrome Developer Console)
 - In Safari, this is the last tab of the developer tools. (How to open Safari Developer Console)
 - In FireFox, this is the tab after Inspector. (How to open Firefox Developer Console)
 
 - The console is like a JavaScript terminal and is a great debugging tool for your later projects. You can type in any JavaScript code, and it will evaluate it line by line, just like an interpreter will. (You can read Google's documentation on Chrome Console)
 - 
                        Type in 
console.log("i love noodles");into the console and hit enter (the semicolon at the end is optional and can be skipped). You'll notice that the message is printed onto the console. This is the equivalent of "printing" to the terminal. (By the way, semicolons are completely optional in JavaScript, you can choose whether to use them or not, but consistency is recommended) - 
                        The console can also evaluate arithmetic expressions. Try typing in 
3 + 4and hitting enter. 
IMPORTANT: We highly recommend getting familiar with the various developer tools in the console, such as the Chrome Debugger for debugging JavaScript. You can use the following brief guide to learn how to set breakpoints and step through JavaScript code to inspect values: https://developers.google.com/web/tools/chrome-devtools/javascript/.
Printing to the console
                    The Console is also a very helpful debugging tool. You can make use of this by printing out to the
                    console directly in your JavaScript code, using the function console.log(). If you have
                    a line in your JavaScript that says console.log("Hello World!"), then when that line is
                    evaluated "Hello World!" will be written to the console. You can console.log() any
                    value in JavaScript, for instance an object or result of a function call, to see if the value is as
                    you expect it to be. You can think of it as similar to printf() or print()
                    in other languages.
                
JavaScript syntax
JavaScript is a pretty wild language, at least because it supports procedural, object-oriented, and functional programming. Here's a little cheat-sheet.
Variables
                    There are three ways to declare a variable with the advent of ES6 (the JavaScript version we are
                    using): var, let, and const. It's a good practice to avoid
                    using var. The current most popular opinion is to always use const when
                    you know the value will not be re-assigned and let if you expect to re-assign the value
                    of the variable (e.g. in a for loop). But be careful! Just because a variable is
                    declared with const does NOT mean that JavaScript will enforce it to be immutable, only
                    that it can not be re-assigned to. For example, a const array can still be appended to,
                    and the values of any keys of a const object can still be modified. You can read more
                    about variable
                        declaration in ES6 here.
                
JavaScript has totally dynamic typing, meaning that you don't need to declare what type a variable is. JavaScript can just figure out the correct type of a variable based on how it's used.
To see this in action, type in the following lines into the JavaScript console (no need to include the comments)
> const lol = "laughing out loud" // strings can be single or double quoted
< undefined
> typeof lol
< "string"
> let numberOfPenguins = 4
< undefined
> typeof numberOfPenguins // should print "number"
< "number"
> numberOfPenguins = 5.0 // we can reassign the value because it is declared using "let"
> typeof numberOfPenguins // all number is JS are type "number" (floating point number)
< "number" 
                As a side note, if you’re curious about why your console returns undefined when you define variables, see here: Why does JavaScript variable declaration at console results in "undefined" being printed?
Arrays
                    Arrays can be of mixed type and are declared through a simple literal syntax that's similar to
                    Python:
                    let mixedTypeArray = ["noodles", {class: "cs1320"}, true, function() {alert("I'm a function")}];
                
Working with arrays:
> mixedTypeArray[0] // access an element, JS array is 0-indexed
< "noodles"
> mixedTypeArray[1] = "CSCI1320" // reassign element value
< "CSCI1320"
> myArray.length // use length to get a total count of elements
< 4
> mixedTypeArray[100] = "Remember to fill out Collab Policy" // add an element at given index
< "Remember to fill out Collab Policy"
                Since arrays are among the most widely used data structures, it may be a good idea to review the following array methods (we have highlighted the ones that we think will be especially important to know): push, pop, shift, unshift, indexOf, includes, splice, sort, and filter. It will also be useful to know the various expressions and operators that can be used with arrays including the spread syntax introduced in ES6, as well as the various array iteration protocols such as basic for loops, for...of loops, and iteration methods such as forEach, and map. You can find all the documentation for arrays on MDN.
Objects
An object in JavaScript is a collection of properties where a property is a mapping from a key (aka name, index...) to a value. Similar to JS Arrays, Objects can also have mixed types.
let captain = {
    name: 'Rockhopper',
    nickname: 'RH',
    location: { // you can have nested objects!
        ship: 'Migrator',
        area: 'Beach'
    }
};
                
                    Write a similar object for yourself in the <script> tags in your index.html. Now
                    open up your page in the browser and check out the JavaScript console. Now type the name of the
                    variable you just made into the console. You should see the name come up with a little arrow to let
                    you inspect the object. You can see all the properties you just defined
                
There are two ways to access a property on an object:
captain['name'] // 'Rockhopper'
                or
captain.name // 'Rockhopper'
                
                    Dot notation is often used for static attribute while bracket notation could accept an attribute
                    name that is dynamically generated. Note that dot notation only works with object properties that
                    are valid identifiers (they must start with a letter and not contain spaces, hyphens, or be keywords
                    like for).
                
If you’re interested, you can also check out some other standard built-in objects that you may find useful, including map and set. ES6 also added some useful ways of using objects, including shorthand for object properties and dynamic property names.
Equality (== vs. ===)
                
                    One of the most common bugs in JavaScript comes from using == rather than
                    ===. They're both equality operators, but with a catch: JavaScript does type coercion.
                    == will coerce its two operands to the same type before comparing them, so
                    1 == "1" is true even though they are not of the same type.
                
                    === on the other hand only returns true if its two operands are equivalent
                    and of the same type. So 1 === "1" is false, since 1 is a
                    number and "1" is a string. It's a best practice to always use
                    === so you don't get any surprises, although there might be situations in which you
                    want to compare two things regardless of type, in which case == is the move.
                
                    For negative equality, != is equivalent to not ==, and !==is
                    equivalent to not ===.
                
You can read more about equality comparisons in this article.
Types of false
                    In JavaScript, variables are "falsy" or "truthy", meaning that you can do
                    if (myNonBooleanVariable)... You can look at definition for truthy and falsy on MDN.
                    Here are the main falsy values.
                
- 
                        
null: Usually used to indicate a nonexistent object,nullis actually of type object, which leads to some confusing things like this:
What happens if you put that in your tags. Is that what you'd expect?if (typeof null === 'object') { alert("JavaScript is weird!"); } - 
                        
undefined: When you try to access a property on an object or a variable that isn't defined, you'll get the valueundefined. Say you have this:
If you're accessing a variable and you're not sure if it'll be there (because, for example, all function arguments are optional in JavaScript), you should check forfunction sayHi(name) { if (name !== undefined) { alert("Hello " + name); } } sayHi() // no output since name is undefined sayHi("CS Student"); // name is "CS Student", you'll get an alertundefined.let myObj = {}; // empty object if (myObj.name === undefined) { console.log("no name!"); // this will always be called } - 
                        
false:falseis useful for values that are definitely known (unlikeundefinedornull) and definitely false. For example,falsemay be assigned to boolean variables (boolean is a data type that has two possible values: true or false). A trivial example:const pigsFly = false; if (pigsFly) { console.log("Club Penguin will shut down"); // this will never happen :'( } 
Surprisingly truthy
Empty arrays and objects always behave like true when treated as booleans.
let info = {};
if (info) {
    console.log("true!");
}
                Summary table of truthy and falsy values in JavaScript
TRUTHY (evaluates to true) | 
                            FALSE (evaluates to false) | 
                        
|---|---|
true | 
                            false | 
                        
| non-zero numbers | 0 | 
                        
"strings" | 
                            "" | 
                        
| objects | undefined | 
                        
| arrays | null | 
                        
| functions | NaN (not a number) | 
                        
Functions
Functions are objects. You can define properties on them, and they're capable of inheritance. Here's some advanced information about JavaScript functions. The gist is:
Declaring functions
There are two standard ways to declare functions:
function myFunction(arg1, arg2, arg3, ...) { ... };
// Example
function add(a, b) {
    return a + b;
};
                const myFunction = function(arg1, arg2, arg3, ...) { ... };
// Example
const add = function(a, b) {
    return a + b;
};
                
                    The first is a normal function or named function, in this case called myFunction. The
                    second is an anonymous function, in which you're assigning to a variable called
                    myFunction. They can almost be used interchangeably, except that the anonymous function
                    is created at run time when the variable is declared, whereas the normal function is run before any
                    other code. In general, it’s a good idea to use anonymous functions when using functions as
                    arguments (think functional programming). You could also instantiate a function object with
                    new Function(), but there aren't many reasons to.
                
As of ES6 syntax, you can also declare functions with the arrow (=>) operator:
const myFunction = (arg1, arg2, arg3, ...) => { ... };
const myFunction = (arg1, arg2, arg3, ...) => { ... };
// Example
const add = (a, b) => a + b; // When the function body can be written in just one line, you can omit the braces { } and return statement. This is purely syntactic sugar.
                
                    This is now one of the most popular ways to declare functions in JavaScript because of two main
                    reasons: 1) it tends to be much more concise to write (see above example) and 2) it resolves some
                    issues relating to the special this variable (to be discussed further in the next
                    section). Although we won’t require the use of any specific form of function declaration, we would
                    recommend using the latest ES6 arrow syntax when possible because it is currently the most popular
                    choice among web devs. Read more about arrow functions on MDN
                    or this feature article: ES6 In Depth: Arrow
                        functions.
                
Calling functions and this
                JavaScript has some cool ways to call functions. Of course, you can call a function by name:
foo();
                or, if it's the property of an object:
const obj = {
    foo: function(){alert('hello, world!');}
};
// by name
obj.foo();
// dynamically: you could assign fn at runtime
const fn = "foo";
obj[fn]();
                
                    Functions have a special variable called this in their scope which can be used to refer
                    to the object that called the function. When a function is called plain (e.g. foo()),
                    this is either the window or the object the function is being called on
                    (which could be an instance of the function object). If the function is called as the property of
                    another object (e.g. obj.foo()) this refers to the object before the
                    . (in this case it would be obj). this can be tricky to
                    understand, and if you find yourself stuck or confused when using it then come to TA hours and/or
                    try checking out this Stack Overflow answer: How does the
                        "this" keyword work?
                
                    One important takeaway from this is that arrow functions do not have their own this
                    binding! Instead, the value of this in an arrow function refers to the same
                    this in the context that the arrow function was defined in. The introduction of the
                    arrow function removes the need for a lot of hacky fixes related to this when
                    programming in JavaScript. You can find a lot of examples about this online, for example here.
                
Expand for further optional reading on instantiating object types ▼
                        In a special case where the function is called with the new keyword,
                        this is bound to an object, and that object is returned. This is the normal way of
                        declaring and instantiating an object type ("class") in JavaScript:
                    
function Cyborg(name) {
    // assign the name property of the `this` object
    this.name = name;
}
const doctor = new Cyborg('Doctor Marbles');
console.log('The name of the doctor is ' + doctor.name); // 'The name of the doctor is Doctor Marbles'
                    
                        If you are familiar with classes in other object-oriented languages, this syntax might confuse
                        you. On one hand, it is used very similarly to a traditional class from other languages, but on
                        the other hand, it's declared as a function. You can think of this like just the constructor of
                        a class. Here, the Cyborg() is a function that's essentially just a constructor for
                        a class called Cyborg. We'll see how to define methods and class methods on this class later on.
                    
                        If you want, you can call a function with a different context, meaning that this
                        can be set to whatever object you want. You do that with call and
                        apply:
                    
foo.apply(otherObj, [ arg1, arg2, arg3 ]); // call foo where this === otherObj
foo.call(otherObj, arg1, arg2, arg3); // these two lines are equivalent
                    
                        The difference is how you supply arguments to the function you're calling. apply
                        takes an array, call takes individual arguments.
                    
Prototypes and inheritance (optional reading) ▼
                        You can define methods on your JavaScript objects using the object's prototype,
                        which is another object that defines properties and methods for the object. You can also define
                        methods inside class function as well.
                    
Put this in your <script> tag:
// this is the constructor for a Friend object
function Friend (name, age, location) {
    this.name = name;
    this.age = age;
    this.location = location;
    this.test = function (){
    return this.name + " " + this.age;
    };
}
// let's define a method for Friend; the prototype is just an object
Friend.prototype = {
    info : function () {
    return this.name + "/" + this.age + "/" + this.location;
    }
};
const penguin = new Friend("Gary", 5, "Pizza Parlor");
console.log(penguin.info());
                    
                        JavaScript doesn't do inheritance the same way C/Java/Python/Ruby does (classically). It uses
                        prototypical inheritance. It looks a little bit confusing (considering there's no
                        inherits or extends keyword. It's actually a really simple concept:
                        when you call a method on an object, JavaScript goes up that object's prototype chain (its
                        parents' prototypes) looking for a method with that name. While that sounds a lot like classical
                        inheritance, it's actually a lot simpler, since it doesn't require any classes or interfaces.
                    
You don't really need multiple inheritance since you can inherit from any list of prototypes in any order you want; they don't have to implement the same methods! Try this out:
                        So what if we want to create an object that inherits from Friend, say, a
                        PenguinFriend? Since we're working with Functions, calling the super-object is as
                        easy as calling a function with the context (this) set to our new object:
                    
function PenguinFriend (name, age, location, hobby) {
    Friend.call(this, name, age, location); // call the parent (like super() in Java)
    this.hobby = hobby;
}
                    
                        Now we want to set PenguinFriend's prototype to an instance of
                        Friend's prototype. We don't want to use Friend's prototype directly
                        because then we'd be messing with Friend. So we create an empty function with a
                        blank constructor so we can instantiate a new Friend prototype:
                    
function emptyFriend() {}; // blank function
emptyFriend.prototype = Friend.prototype;
PenguinFriend.prototype = new emptyFriend(); // a new instance of the prototype
PenguinFriend.prototype.constructor = PenguinFriend; // that's the function that the new keyword calls
                    
                        Nice! Now we've got a PenguinFriend using its constructor but Friend's
                        prototype. How do we add new methods? Just define them on the prototype object:
                    
PenguinFriend.prototype.profile = function () {
    return this.info() + "/" + this.hobby;
}
                    Now if you've been following along, you should be able to do this:
const matt = new PenguinFriend("Matt", 11, "Ohio", "Skateboarding");
console.log(matt.profile());
                    This can get pretty confusing and might be worth reading twice. Evan Wallace also has a section on the same topic in JavaScript for Coders.
Classes (optional reading) ▼
As part of ES6, standard class declarations have been introduced to JavaScript. The class syntax is not introducing a new object-oriented inheritance model to JavaScript, it is syntactic-sugar for prototypical inheritance. JavaScript classes provide a simpler and clearer syntax to create objects. For more information on classes checkout this information from Mozilla.
class TA{
    constructor(height, hairColor){
        this.height = height;
        this.hairColor = hairColor;
    }
    gradeHomework(hwk) {
        // code not shown ...
    }
}
                    Function and class declarations are different because function declarations are hoisted and class declarations are not. You first need to declare your class and then access it; otherwise an error will be thrown.
Scoping
                    Unlike C/Java/Python and other languages you are probably familiar with, Javascript has function
                        scoping rather than block scoping. So if statements, while loops,
                    etc. do not create a scope, and variables defined with var are hoisted to be declared
                    at the beginning of their scope. This is also a reason why let and const
                    are better practice than var, since they don't exhibit this sort of
                        behavior. Scoping is the source of many errors when using JavaScript. For more information,
                    check out this great StackOverflow
                        answer about Variable Scope in JavaScript.
                
Closure (optional reading) ▼
JavaScript functions can access variables accessible but not declared within their scope at any time.
function counter(){
    let count = 0;
    return function(){
        // [count] here is the [count] from above
        count++;
        return count;
    }
}
let c = counter();
c() // 1
c() // 2
c() // 3
// ...
                    
                        This type of setup is useful especially when variables shouldn't be accessible -- there's no way
                        for external code to change count (on the other hand, if it were the property of an
                        object anything could read and write it).
                    
Another place this becomes useful is maintaining a reference to an object in event handlers and the like:
//This defines a single Timer object (like a singleton class,
//only one exists and you can't instantiate it).
let Timer = {
    count: 0,
    render: function () {
        console.log(this.count);
    },
    initialize: function () {
        //this puts a reference to [this] in this scope
        //which won't be overridden by the [this] in the scope
        //of functions defined later.
        let manager = this;
        //setInterval calls [argument1] every [argument2] milliseconds.
        setInterval(function () {
            //this reference to manager is maintained, while [this] now
            //references the function as passed to setInterval in this
            //scope.
            manager.count++;
            manager.render();
        }, 1000);
    }
};
                Other syntax
Conditionals
                    JavaScript conditionals are a lot like C. There is if, else if, and
                    else. We already talked about truthy and falsy values. You can convert a variable to a
                    boolean type with !!(not not), so !!1 === true. This is a good way to
                    determine if a value is "truthy" or "falsy" (just do console.log(!!myValue);. You can
                    also use the Boolean() function for the same effect.
                
JavaScript also has a switch statement:
function legal(age) {
    let ableTo = [];
    switch (age) {
        case 18:
            ableTo.push('vote', 'fight', 'get real estate license');
            break;
        case 21:
            ableTo.push('drink', 'gamble');
            break;
        case 65:
            ableTo.push('retire');
            break;
        default:
            ableTo.push('be free');
    }
    return ableTo;
}
                Loops
Similar deal here. It looks just like C:
for (let i=0; i < someArray.length; i++){
    console.log(someArray[i]);
}
                One difference is that you can also iterate over an object or array:
for (let key in object) {
    console.log("key: " + key + " value: " + object[key]);
}
for (let index in array) {
    console.log("index: " + index + " value: " + array[index]);
}
                
                    Note that when used for the object case, this syntax gives you all the keys defined on the object
                    including keys of its prototypes. That can lead to some unpleasant surprises, so in this case one
                    would either use hasOwnProperty, which returns true if and only if the
                    property name is defined for that object directly, or use something like Object.entries
                    which only gets the object’s own keys. You DO NOT need to use this sort of syntax with arrays,
                    because key would just be the index in the array, and this type of loop is slower.
                
for (let key in object) {
    if (!object.hasOwnProperty(key)){continue;}
    console.log("key: " + key + " value: " + object[key]);
}
// or using Object.entries() - this tends to be the popular choice
for (let [key, value] of Object.entries(object)) {
    console.log("key: " + key + " value: " + value);
}
                
                    JavaScript also has while loops just like C/Java, and you can use
                    ++/-- unary operators on values. JavaScript also has a break
                    keyword for getting out of a loop and a continue statement for going to the next
                    iteration.
                
Events
If you haven't already, try clicking the box above. Wow! We were able to add this interactive functionality to this webpage using JavaScript to listen for a click event on the above div. But what are events? The DOM makes a ton of use of the delegate event model, meaning that when something happens in the browser, it emits events, which can be picked up (and modified) by any code that's listening. This makes it easy for programmers to add additional code to a page without worrying about other scripts (e.g. plugins, bookmarklets, frames), and allows for really decoupled design. Let's see another example:
                    Here is some syntax for adding event listeners to an object. It's nice because you can add and
                    remove multiple listeners for the same event: Add this HTML between your body tags:
                    <div id="display">press a key</div>. We're going to set up event
                    listeners for keyup, so you can see when the user presses a key. Add the following code
                    between the <script> tags in index.html:
                
const display = document.getElementById('display');
// Here we're going to make use of an anonymous function.
// Since functions are like any other object (number, string, etc.)
// in JavaScript, we can pass a function as an argument to another function
// without issue!
document.addEventListener('keyup', function (event) {
    // the event object can tell us which key is pressed
    display.textContent = "you pressed key #" + event.keyCode;
}, false);
                Reload the page, and try pressing any key. The text should change and indicate the key that was pressed.
Keyboard keys in javascript are identified by their keys and codes. So to only do something when the user hits "enter":
document.addEventListener('keyup', function (event) {
    if (event.key === "Enter") {
        console.log("you hit enter!");
    }
}, false);
                
                    Notice that we're adding the event listener to document. The document is
                    an element like any other, referring to everything inside the <html> tags. We're
                    just adding the listener there because we want to call it on a keypress anywhere on the
                    page. Events bubble up the DOM tree: if you click a button, you can listen to that event on any
                    parent element of the button (which can sometimes be tricky if you weren't expecting to get that
                    event there).
                
As another example, here is the code we used to create the click listener for the "You clicked me!" div above:
<div id="onclick-div" style="background-color: #FEBB14; padding: 15px; border: 4px solid #D64D37; margin-bottom: 20px; width: 300px; user-select: none">Try clicking me!</div>
<script>
    let counter = 0;
    const onclickDiv = document.getElementById("onclick-div");
    onclickDiv.addEventListener("click", function(event) {
        counter++;
        if (counter < 5) {
            onclickDiv.innerHTML = "You clicked me! (" + counter + ")";
        } else {
            onclickDiv.innerHTML = "Ok, please stop clicking me now ;-; (" + counter + ")";
        }
    });
</script>
                
                    innerHTML is a property of an element which represents its contents as HTML. Here we
                    use it just to change the text inside the div, but we could also add more elements inside the div
                    (so assigning onclickDiv.innerHTML = "<em>content</em>" will show
                    a div with the word "content" inside of it italicized).
                
                    This is opposed to textContent which also represents the contents of an element, but as
                    text. Any tags inside it are ignored, and any tags put into it are represented literally as text.
                    (So assigning onclickDiv.textContent = "<em>content</em>" will
                    show a div with the words "<em>content</em>", not italicized).
                
preventDefault and stopPropagation
                
                    Events have default behaviors depending on what triggered the event. For example, on a text input,
                    the default behavior of a key press event is to add the key that was pressed to the value of the
                    input. However, there are times when you might not always want the default behavior to happen and
                    that is where preventDefault becomes useful. For example, if we wanted our text input
                    to only accept lowercase letters, we could attach the following key press handler to our text input:
                
<input type="text" id="lowercase-input">
<script>
    const lowercaseInput = document.getElementById("lowercase-input");
    lowercaseInput.addEventListener("keypress", function(event) {
        const key = event.charCode
        if (key !== 0 && (key < 97 || key > 122)) {
            event.preventDefault();
        }
    });
</script>
                
                    stopPropagation is useful when you want to prevent further propagation of the current
                    event in the capturing and bubbling phases. Event bubbling in JavaScript describes the order in
                    which event handlers are called when one element is nested inside a second element, and both
                    elements have registered a listener for the same event (such as a click). For example:
                
<div id="parent">
    <button id="child">click me</button>
</div>
<script>
    const child = document.getElementById("child");
    child.addEventListener("click", function(event) {
        console.log("child clicked");
    });
    const parent = document.getElementById("parent");
    parent.addEventListener("click", function(event) {
        console.log("parent clicked");
    });
</script>
                Clicking on the button would result in the console printing “child clicked” then “parent clicked”. However if you don’t want the click event to propagate to the parent and want to prevent the parent from printing, you can change the child’s click listener to the following:
child.addEventListener("click", function(event) {
event.stopPropagation();
    console.log("child clicked");
});
            What is the DOM?
From the W3C (the people who design web standards):
The Document Object Model (DOM) is an application programming interface (API) for valid HTML and well-formed XML documents. It defines the logical structure of documents and the way a document is accessed and manipulated. In the DOM specification, the term "document" is used in the broad sense.
                    The DOM represents elements (i.e. <a>, <div>,
                    <p>) as nodes in a tree. These nodes are available as objects in JavaScript. You
                    may find that you will often want to manipulate the document (we have already seen this, e.g. when
                    we used getElementById() or innerHTML). If you want, you can read more
                    about manipulating objects here.
                
A quick note on asynchronous programming in JavaScript
This is a fairly advanced but essential part of programming in JavaScript that we won’t go into great depth for the purposes of this prelab. After you’ve had a chance to process and digest the other information, we recommend doing a little independent research on this topic. If you don’t already know what asynchronous programming means, we recommend checking out this introduction. In short, although the JavaScript language is synchronous and single threaded by default, many things that JavaScript is used for needs an asynchronous approach. For example, one of JavaScript’s main jobs is to respond to user actions such as onClick, onMouseOver, onChange, onSubmit, which require an asynchronous approach. The JavaScript environment (browser) provides a set of API functionality that can handle this asynchronous functionality. However, this can result in problems when using variables that we expect to have a certain value but end up not being defined because the event (asynchronous) hasn’t completed yet.
The classic fix for this was the use of a callback function, which is passed as an argument to another function and only has its code executed when the event happens. As of ES6, Promises (highly recommended to look into!) were introduced as the new method of asynchronous programming and can be used to avoid a bunch of the problems with using callbacks. Promises can also be used with async functions and the await keyword introduced in 2017, and this is now arguably the best way to program asynchronously in JavaScript. You may find the following tutorials helpful down the road:
Promises in JavaScript with ES6 / ES2015Exploring Async/Await Functions in JavaScript
Looking ahead: Using JSDoc + ESLint:
In addition, there are two widely used JavaScript add-ons that you should be aware of which we would like you to use in your assignments: JSDoc and ESLint. JSDoc allows you to add annotations to your JavaScript code, making it easier for you and other programmers to read your code. ESLint is used to help find bugs and errors in your code by statically analyzing it. It can be installed as a plugin with VS Code or configured as part of your Node.js project using npm.
Tasks:
Open the stencil
- Task 1: Move the EventListener for click-button to the 
script.jsfile and invoke it in yourindex.htmlfile - Task 2: Add the following functionality to the form: Write a function that adds the three inputted values together
                    and then print this value in the 
index.htmlpage Feel free to style it, but it is not required for this lab! 
This is the end of the prelab! It is a lot to digest, so if you're confused about anything, feel free to come to TA Hours.
Handin Instructions
- To hand in your code for prelab 3,  commit and push your changes to your cloned GitHub Classroom repository's 
mainbranch. - And submit it on gradescope using this link. Please note that you'll have to submit it to gradescope this time or we'll not be able to grade your submission.