JavaScript

Réussis tes devoirs et examens dès maintenant avec Quizwiz!

NODES

there are many different types of nodes, but the ones we will most often be working with are ELEMENT_NODE and TEXT_NODE (you can see them all here). Element nodes are HTML elements (div, span etc.). Text nodes are the actual text of an element node.

Very often you'll need to convert a value from one type

to another

What is localStorage?

localStorage is a mechanism for storing information in the browser for a specific domain. The API is quite easy to use and very minimal - so let's get started with it!

If you ever want to determine if a value is truthy or falsey, you can prefix it with

!!

difference between class and object syntax

Although you may see similarities between class and object syntax, there is one important method that sets them apart. It's called the constructor method. JavaScript calls the constructor() method every time it creates a new instance of a class. JavaScript will invoke the constructor() method every time we create a new instance of our Dog class.

In JavaScript, if we do not specifically tell the function to return something, it will return undefined when it is finished executing.

Use the return keyword Once it is executed, the function is complete and no other lines of code will be executed. Return can only be used in a function

DOM manipulation

We can change the text of an element through the innerHTML or innerText property. innerHTML will include the syntax

Method makes a copy of an array or creates a subarray

slice with no arguments it simply creates a copy. can pass in two arguments, first to indicate where to start subarray in index, second to indicate where to end. var arr = [7, 6, 5, 4, 3, 2]; arr.slice(1, 2); // [6] arr.slice(2, 5); // [5, 4, 3] arr.slice(2, 1); // []

Converting to a string

toString The toString method will convert any value which is not undefined or null into a string. Here are a couple of examples: var num = 5; var bool = true; num.toString(); // "5"; bool.toString(); // "true";

Accessing characters in a string

var name = "Matt"; name[0]; // "M" Note: cant reassign characters this way

heap

where objects are stored. The heap is an unstructured/unorganized region of memory.

function anyNameYouWantForTheFunction() { // As many lines of code as you want } this type of function syntax consists of four parts:

1. The function keyword, 2. The name of the function (in this case, anyNameYouWantForTheFunction), 3. Any parameters for the function (we'll ignore this for now, but parameters will go inside of the parentheses after the function name), 4. The function body (the code for the function, which lives inside of the curly braces).

some values (aside from false) are actually false as well, when they're used in a context where JavaScript expects a boolean value. In JavaScript there are 6 falsey values:

0 "" null undefined false NaN (short for not a number)

Adding event listeners to parent elements

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <ul> Ingredients <li>Sugar</li> <li>Milk</li> <li>Eggs</li> <li>Flour</li> <li>Baking Soda</li> </ul> </body> </html> In order to alert the text of whatever element we looked for, we can either listen on the parent or listen on each child. Let's examine both options: // OPTION 1: listening on the parent var ul = document.querySelector("ul"); // how many event listeners? ul.addEventListener("click", function(event){ alert("You just clicked on " + event.target.innerText); }); // OPTION 2: listening on the children var listItems = document.getElementsByTagName("li"); // how many event listeners? for(var i=0; i<listItems.length; i++){ listItems[i].addEventListener("click", function(event){ alert("You just clicked on " + event.target.innerText); }); } which one do you think is more efficient? If you guessed the one with fewer listeners, you are right! It's always best to have fewer event listeners, as they consume memory and are difficult to manage when there are many of them.

== vs. ===

== allows for type coercion of the values, while === does not.

Callback function

A callback function, also known as a higher-order function, is a function that is passed to another function (let's call this other function "otherFunction") as a parameter, and the callback function is called (or executed) inside the otherFunction. A callback function is essentially a pattern (an established solution to a common problem), and therefore, the use of a callback function is also known as a callback pattern. Consider this common use of a callback function in jQuery: //Note that the item in the click method's parameter is a function, not a variable.​ ​//The item is a callback function $("#btn_1").click(function() { alert("Btn 1 Clicked"); }); As you see in the preceding example, we pass a function as a parameter to the click method. And the click method will call (or execute) the callback function we passed to it. This example illustrates a typical use of callback functions in JavaScript, and one widely used in jQuery. Ruminate on this other classic example of callback functions in basic JavaScript: var friends = ["Mike", "Stacy", "Andy", "Rick"]; ​ friends.forEach(function (eachName, index){ console.log(index + 1 + ". " + eachName); // 1. Mike, 2. Stacy, 3. Andy, 4. Rick​ });

Getter and Setter methods

A common object design paradigm is to include getter and setter methods as attributes. Getter and setter methods get and set the properties inside of an object. There are a couple of advantages to using these methods for getting and setting properties directly: You can check if new data is valid before setting a property. You can perform an action on the data while you are getting or setting a property. You can control which properties can be set and retrieved. let restaurant = { _name: 'Italian Bistro', _seatingCapacity: 120, _hasDineInSpecial: true, _entrees: ['Penne alla Bolognese', 'Chicken Cacciatore', 'Linguine pesto'], set seatingCapacity(newCapacity) { if (typeof newCapacity === 'number') { this._seatingCapacity = newCapacity; console.log(`${newCapacity} is valid input.`); } else { console.log(`Change ${newCapacity} to a number.`) } } } The code below calls the setter method: // Sets the _seatingCapacity value to 150 restaurant.seatingCapacity = 150;

instance

An instance is an object that contains the property names and methods of a class, but with unique property values. Let's look at our Dog class example. class Dog { constructor(name) { this.name = name; this.behavior = 0; } } const halley = new Dog('Halley'); // Create new Dog instance

Traversing the DOM

Another very common operation when working with the DOM is trying to find elements inside of other elements. When we travel through the DOM in search of something, we are doing what is called DOM traversal Examples: var container = document.getElementById("container"); container.childNodes; // // this contains all of the nodes (including text nodes) that are children container.childNodes.length; // 11 container.children; // this contains all of the elements that are children of the element we have selected container.children.length; // 5 var link = document.querySelector("a"); link.parentElement; // <body id="container">...</body> link.previousElementSibling; // <div class="hello">Hello Everyone!</div> link.previousSibling; // text node link.nextSibling; // text node link.nextElementSibling; // <button>​Click me!​</button>​

classes

Classes are a tool that developers use to quickly produce similar objects. class Dog { constructor(name) { this._name = name; this._behavior = 0; } get name() { return this._name; } get behavior() { return this._behavior; } incrementBehavior() { this._behavior ++; } } const halley = new Dog('Halley'); note: Class method and getter syntax is the same as it is for objects except you can not include commas between methods.

Method joins to arrays together

Concat var arr1 = [1,2,3]; var arr2 = [4,5,6]; var combined = arr1.concat(arr2); combined; // [1,2,3,4,5,6] Can pass multiple arrays in. var arr1 = ["a","b","c"]; var arr2 = ["d","e","f"]; var arr3 = ["g","h","i"]; var combined = arr1.concat(arr2,arr3); combined; // ["a","b","c","d","e","f","g","h","i"]; Note: Works for any list seperated by commas (doesn't have to be an array) var openingWords = ["It","was","a"]; var moreOpeningWords = openingWords.concat("dark","and","stormy","night"); moreOpeningWords; // ["It", "was", "a", "dark", "and", "stormy", "night"]

static keyword

Creates methods that can only be accessed when calling the object. Instances do not inherit. Let's see how to use the static keyword to create a static method called generateName method in our Animal class: class Animal { constructor(name) { this._name = name; this._behavior = 0; } static generateName() { const names = ['Angel', 'Spike', 'Buffy', 'Willow', 'Tara']; const randomNumber = Math.floor(Math.random()*5); return names[randomNumber]; } } In the example above, we create a static method called .generateName() that returns a random name when it's called. Because of the static keyword, we can only access .generateName() by appending it to the Animal class. We call the .generateName() method with the following syntax: console.log(Animal.generateName()); // returns a name You cannot access the .generateName() method from instances of the Animal class or instances of its subclasses (See below). const tyson = new Animal('Tyson'); tyson.generateName(); // TypeError

Hoisting In Function Declarations vs Function Expressions

Function declarations are fully defined before the code is run. So in the following example, we can call the sayHi function above the lines that define the sayHi function: sayHi("Matt"); // "Hello Matt" function sayHi(name){ return "Hello " + name; } function expressions act differently. Since a function expression assigns an anonymous function to a variable, hoisting applies to that variable name as well. In the following example, there is an error because we are trying to invoke a function called sayHi but at that point in the code sayHi is not equal to a function. In fact, sayHi exists in memory but it is undefined. sayHi("Matt"); // Throws an error! var sayHi = function(name){ return "Hello " + name; }

Adding an event to wait for the DOM to load

If our script tag is running before the DOM has loaded, it has no idea what the <div id="container"></div> is! What we can do is wait for the DOM to load before executing any JavaScript. This can be done either with the load event or the DOMContentLoaded event. <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script> document.addEventListener("DOMContentLoaded", function(){ var container = document.getElementById("container"); container.innerText = "Hello World"; // This works now! }); </script> </head> <body> <div id="container"> </div> </body> </html>

Callback functions - Use Named OR Anonymous Functions as Callbacks

In the earlier jQuery and forEach examples, we used anonymous functions that were defined in the parameter of the containing function. That is one of the common patterns for using callback functions. Another popular pattern is to declare a named function and pass the name of that function to the parameter. Consider this: // global variable​ ​var allUserData = []; ​ ​// generic logStuff function that prints to console​ ​function logStuff (userData) { if ( typeof userData === "string") { console.log(userData); } else if ( typeof userData === "object") { for (var item in userData) { console.log(item + ": " + userData[item]); } ​ } ​ } ​ ​// A function that takes two parameters, the last one a callback function​ ​function getInput (options, callback) { allUserData.push (options); callback (options); ​ } ​ ​// When we call the getInput function, we pass logStuff as a parameter.​ ​// So logStuff will be the function that will called back (or executed) inside the getInput function​ getInput ({name:"Rich", speciality:"JavaScript"}, logStuff); ​// name: Rich​ ​// speciality: JavaScript

Callback functions - Make Sure Callback is a Function Before Executing It

It is always wise to check that the callback function passed in the parameter is indeed a function before calling it. Also, it is good practice to make the callback function optional. Let's refactor the getInput function from the previous example to ensure these checks are in place. function getInput(options, callback) { allUserData.push(options); ​ // Make sure the callback is a function​ if (typeof callback === "function") { // Call it, since we have confirmed it is callable​ callback(options); } } Without the check in place, if the getInput function is called either without the callback function as a parameter or in place of a function a non-function is passed, our code will result in a runtime error.

What is JSON?

JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to read and write. It is easy for machines to parse and generate. JavaScript has a built-in JSON object, and on this object are two methods used to convert JavaScript data into JSON, and to parse JSON strings into JavaScript. The JSON object itself can't be called or constructed, and aside from its two methods it has no interesting functionality of its own. JSON.stringify is used to convert JavaScript to JSON (or stringify) JSON.parse parses a string as JSON. Using these two methods allows us to preserve the intended data structure when it is something other than a string: var instructors = ["Elie", "Matt", "Tim"]; // the JSON.stringify call converts the instructors array into a JSON string localStorage.setItem("instructors", JSON.stringify(instructors)); // JSON.parse converts the JSON string back into JavaScript (in this case, a valid array) JSON.parse(localStorage.getItem("instructors"));

Make Your Own Callback Functions

Now that you completely (I think you do; if not it is a quick reread :)) understand everything about JavaScript callback functions and you have seen that using callback functions are rather simple yet powerful, you should look at your own code for opportunities to use callback functions, for they will allow you to: Do not repeat code (DRY—Do Not Repeat Yourself) Implement better abstraction where you can have more generic functions that are versatile (can handle all sorts of functionalities) Have better maintainability Have more readable code Have more specialized functions. It is rather easy to make your own callback functions. In the following example, I could have created one function to do all the work: retrieve the user data, create a generic poem with the data, and greet the user. This would have been a messy function with much if/else statements and, even still, it would have been very limited and incapable of carrying out other functionalities the application might need with the user data. Instead, I left the implementation for added functionality up to the callback functions, so that the main function that retrieves the user data can perform virtually any task with the user data by simply passing the user's full name and gender as parameters to the callback function and then executing the callback function. In short, the getUserInput function is versatile: it can execute all sorts of callback functions with myriad of functionalities. // First, setup the generic poem creator function; it will be the callback function in the getUserInput function below.​ ​function genericPoemMaker(name, gender) { console.log(name + " is finer than fine wine."); console.log("Altruistic and noble for the modern time."); console.log("Always admirably adorned with the latest style."); console.log("A " + gender + " of unfortunate tragedies who still manages a perpetual smile"); } ​ ​//The callback, which is the last item in the parameter, will be our genericPoemMaker function we defined above.​ ​function getUserInput(firstName, lastName, gender, callback) { var fullName = firstName + " " + lastName; ​ // Make sure the callback is a function​ if (typeof callback === "function") { // Execute the callback function and pass the parameters to it​ callback(fullName, gender); } } Call the getUserInput function and pass the genericPoemMaker function as a callback: getUserInput("Michael", "Fassbender", "Man", genericPoemMaker); ​// Output​ ​/* Michael Fassbender is finer than fine wine. Altruistic and noble for the modern time. Always admirably adorned with the latest style. A Man of unfortunate tragedies who still manages a perpetual smile. */ Because the getUserInput function is only handling the retrieving of data, we can pass any callback to it. For example, we can pass a greetUser function like this: function greetUser(customerName, sex) { var salutation = sex && sex === "Man" ? "Mr." : "Ms."; console.log("Hello, " + salutation + " " + customerName); } ​ ​// Pass the greetUser function as a callback to getUserInput​ ​getUserInput("Bill", "Gates", "Man", greetUser); ​ ​// And this is the output​ Hello, Mr. Bill Gates We called the same getUserInput function as we did before, but this time it performed a completely different task. As you see, callback functions afford much versatility. And even though the preceding example is relatively simple, imagine how much work you can save yourself and how well abstracted your code will be if you start using callback functions. Go for it. Do it in the monings; do it in the evenings; do it when you are down; do it when you are k Note the following ways we frequently use callback functions in JavaScript, especially in modern web application development, in libraries, and in frameworks: For asynchronous execution (such as reading files, and making HTTP requests) In Event Listeners/Handlers In setTimeout and setInterval methods For Generalization: code conciseness

Holds keys and values

Objects var firstObj = { firstName: "Tim" lastName: "Garcia", isInstructor: true };

why use higher order functions?

One advantage of higher order functions is code reuse. Instead of writing five different functions, we can just write one and pass another function to it! We call a function that is passed as an argument to a higher order function a callback.

Use Bracket notation when wanting to place a variable into an object

One advantage that bracket notation has over dot notation is that you can use variables inside the brackets to select the keys of an object. Note: With this you don't use quotes let meal = 'none'; let time = 12; // We'll use military time for this example, counting hours 0-23. const restaurantSpecials = { breakfast: 'The breakfast special is 20% off freshly squeezed orange juice', lunch: 'The lunch special is 10% off appetizers', none: 'There are no specials currently' }; if (time < 11) { // 11 am meal = 'breakfast'; } else if (time < 17) { // 5 pm meal = 'lunch'; } console.log(restaurantSpecials[meal]); Bracket notation is required to use variables to look up keys within an object. It's not possible to use variables like this with dot notation.

The context in which values and expressions are 'visible,' or can be referenced

Scope

Callback functions -Pass Parameters to Callback Functions

Since the callback function is just a normal function when it is executed, we can pass parameters to it. We can pass any of the containing function's properties (or global properties) as parameters to the callback function. In the preceding example, we pass options as a parameter to the callback function. Let's pass a global variable and a local variable: //Global variable​ ​var generalLastName = "Clinton"; ​ ​function getInput (options, callback) { allUserData.push (options); ​// Pass the global variable generalLastName to the callback function​ callback (generalLastName, options); }

Adding objects

So far we have only added primitives, which is nice and easy, but what happens when we start adding objects? Well, things get a bit trickier.... Let's see what happens: var instructors = ["Elie", "Matt", "Tim"]; localStorage.setItem("instructors", instructors); localStorage.getItem("instructors"); When we get the instructors from localStorage, we don't have an array anymore - we have a string! Remember, when dealing with localStorage, everything gets converted into a string. In order to get back our original data type, we need to briefly introduce something called JSON

Changing multiple elements

So what would happen if we wanted to change all of our divs to have a background color of red? Unfortunately, we can not do that without a loop: var divs = document.querySelectorAll("div"); divs.style.backgroundColor = "red"; // this will not work, try to understand the error you receive! // we have to use a loop for each one instead. for(var i = 0; i < divs.length; i++){ divs[i].style.backgroundColor = "red"; // this will work! }

DOM Event

So what would happen if we wanted to change all of our divs to have a background color of red? Unfortunately, we can not do that without a loop: var divs = document.querySelectorAll("div"); divs.style.backgroundColor = "red"; // this will not work, try to understand the error you receive! // we have to use a loop for each one instead. for(var i = 0; i < divs.length; i++){ divs[i].style.backgroundColor = "red"; // this will work! } In a nutshell, events are things we can trigger by interacting with the browser. Here are some potential events we can listen (and then execute some code) for: - clicking on something - hovering over something with the mouse - pressing certain keys - when the DOM has loaded - when a form is submitted

Removing an event listener

Sometimes we want to stop listening for events. To do that we use the removeEventListener method, but it has some quirks you should be aware of. Assuming you've still got those alert messages being triggered when you click on a button, let's take a look at the following code: In order to successfully remove an event listener, the callback that we pass in can't be an anonymous function. // In order to remove, we have to name our function before adding it instead of adding an anonymous function function alertData(){ alert("You just clicked a button"); } for(var i=0; i<buttons.length; i++){ buttons[i].addEventListener("click", alertData); } // since we have named our function, we know which one to remove for(var i=0; i<buttons.length; i++){ buttons[i].removeEventListener("click", alertData); }

What is the DOM?

The Document Object Model is a programming interface for HTML, XML and SVG documents. It provides a structured representation of the document as a tree. The DOM defines methods that allow access to the tree, so that they can change the document structure, style and content. The DOM provides a representation of the document as a structured group of nodes and objects, possessing various properties and methods. Nodes can also have event handlers attached to them, and once an event is triggered, the event handlers get executed. Essentially, it connects web pages to scripts or programming languages. To access the DOM, we make use of the document object. This object has properties and functions that we use to access our HTML elements which we can manipulate with JavaScript.

How to access elements in the DOM

The easiest way to select elements is by their id using the getElementById function on the document object (document.getElementById). This returns a SINGLE element (because ids must be unique!). var container = document.getElementById("container"); We can also use a function called querySelector, which selects a SINGLE element using CSS selectors. If multiple elements match the query you pass in to querySelector, the function will simply return the first matching element that it finds. var container = document.querySelector("#container"); Notice that when we select by id using querySelector, we pass in the string #container, not container. Remember: querySelector always expects a CSS selector. In contrast, when we use getElementById, we just pass in the string container (no hashtag)! Since getElementById expects to find an element by id, in this case the hashtag isn't necessary. To select multiple elements, we can use getElementsByTagName or getElementsByClassName, or we can use querySelectorAll and pass in a CSS selector. These will return what appear to be arrays (they are not exactly arrays, but for right now, that is not a problem). var divs = document.getElementsByTagName("div"); var divs = document.querySelectorAll("div"); Here is another example using getElementsByClassName and the same thing with querySelectorAll. var divsWithClassOfHello = document.getElementsByClassName("hello"); var divsWithClassOfHello = document.querySelectorAll(".hello"); As you can see, when you pass in a class name using getElementByClassName, you don't need to start the string with a dot. The function expects to receive a class name - it's in the name of the function! On the other hand, querySelectorAll takes in any valid CSS query, which is why you need to pass in .hello if you want it to find all elements with a class of "hello."

localStorage vs sessionStorage

The localStorage property allows you to access a local Storage object. localStorage is similar to sessionStorage. The only difference is that, while data stored in localStorage has no expiration time, data stored in sessionStorage gets cleared when the browsing session ends—that is, when the browser is closed. What this basically means is: sessionStorage maintains a separate storage area for each given origin that's available for the duration of the page session (as long as the browser is open, including page reloads and restores) localStorage does the same thing, but persists even when the browser is closed and reopened.

retrieving from local storage

The most important thing to remember is that all of your keys in localStorage or sessionStorage must be STRINGS. localStorage stores everything as strings, so it's just good to get in the habit of setting your keys as strings to avoid confusion. To set something into localStorage we use the setItem method and to retrieve we use the getItem method (only passing in the key) localStorage.setItem("instructor", "Elie"); localStorage.setItem("favoriteNumber", 18); localStorage.setItem("isHilarious", true); localStorage.getItem("instructor"); // "Elie" If you refresh the page - you should be able to still retrieve these keys in localStorage

What we have just created is a small module, which is a piece of code that is encapsulated and can be reused quite easily.

The pattern we just used to write our code is famously called the module pattern! It's a great way to wrap everything in an IIFE that contains private data that can not be accessed globally. We can even refactor this more so that our logic is not in the return statement. var instructorModuleRefactored = (function createInstructors(){ var instructors = ["Elie", "Matt", "Tim"]; function displayAllInstructors(){ return instructors; } function addNewInstructor(instructor){ instructors.push(instructor); return instructors; } return { showInstructors: displayAllInstructors, addInstructor: addNewInstructor } })();

Adding an event listener

There are three ways that we can add event listeners to our code. Given an element we want to listen to, and a function we want to execute, we can either attach the name of the function to the element in HTML, in JavaScript, or we can use the addEventListener method. Here's some JavaScript code that highlights each one of these approaches: // Option 1: - directly in HTML. Note that in your HTML, // the first button makes reference to a function called firstClick // in the onclick attribute function firstClick(){ alert("you clicked the first button!"); } // Option 2 - attach the function to the element var secondButton = document.querySelector('.second_button'); secondButton.onclick = function(){ alert("you clicked the second button!"); } // Option 3 - use addEventListener var thirdButton = document.querySelector('.third_button'); thirdButton.addEventListener("click", function(){ alert("you clicked the third button!"); }); It is often best to either use the second or third option, as these are a bit more customizable, but it is good to know all of your options. Note: Just like when changing multiple elements, we need to iterate through each one - we cannot just add an event listener to an array-like object of element nodes.

removing from localStorage

To delete a key we use the removeItem function, and to clear everything from localStorage for this domain we use clear: localStorage.removeItem("instructor"); localStorage.clear();

CSS DOM Manipulation

We can also directly manipulate the CSS properties for elements (through inline styling) with the style property. var firstDiv = document.getElementsByTagName("div")[0]; firstDiv.style.color = "red"; firstDiv.style.backgroundColor = "teal"; Notice that if you're accessing CSS properties using dot notation, you need to camelCase those property names, since firstDiv.style.background-color is invalid JavaScript. However, if you use brackets, you can write the properties the same way as you would in a stylesheet: firstDiv.style["background-color"] = "purple"; // this works too If we want to access/modify attributes on elements, we can do that with getAttribute and setAttribute: var body = document.getElementById("container"); body.getAttribute("id"); // "container" body.setAttribute("id", "new_container"); body.getAttribute("id"); // "new_container" We can also add and remove classes to elements using classList var secondDiv = document.getElementsByTagName("div")[1]; secondDiv.classList; // ["hello"] secondDiv.classList.add("another_class"); secondDiv.classList; // ["hello", "another_class"] secondDiv.classList.remove("hello"); secondDiv.classList; // [another_class"]

Callback functions - Use the Call or Apply Function To Preserve this

We can fix the preceding problem by using the Call or Apply function (we will discuss these in a full blog post later). For now, know that every function in JavaScript has two methods: Call and Apply. And these methods are used to set the this object inside the function and to pass arguments to the functions. Call takes the value to be used as the this object inside the function as the first parameter, and the remaining arguments to be passed to the function are passed individually (separated by commas of course). The Apply function's first parameter is also the value to be used as the this object inside the function, while the last parameter is an array of values (or the arguments object) to pass to the function. This sounds complex, but lets see how easy it is to use Apply or Call. To fix the problem in the previous example, we will use the Apply function thus: //Note that we have added an extra parameter for the callback object, called "callbackObj"​ ​function getUserInput(firstName, lastName, callback, callbackObj) { // Do other stuff to validate name here​ ​ // The use of the Apply function below will set the this object to be callbackObj​ callback.apply (callbackObj, [firstName, lastName]); } ​ With the Apply function setting the this object correctly, we can now correctly execute the callback and have it set the fullName property correctly on the clientData object: // We pass the clientData.setUserName method and the clientData object as parameters. The clientData object will be used by the Apply function to set the this object​ getUserInput ("Barack", "Obama", clientData.setUserName, clientData); ​ ​// the fullName property on the clientData was correctly set​ console.log (clientData.fullName); // Barack Obama We would have also used the Call function, but in this case we used the Apply function.

How Callback Functions Work?

We can pass functions around like variables and return them in functions and use them in other functions. When we pass a callback function as an argument to another function, we are only passing the function definition. We are not executing the function in the parameter. In other words, we aren't passing the function with the trailing pair of executing parenthesis () like we do when we are executing a function. And since the containing function has the callback function in its parameter as a function definition, it can execute the callback anytime. Note that the callback function is not executed immediately. It is "called back" (hence the name) at some specified point inside the containing function's body. So, even though the first jQuery example looked like this: //The anonymous function is not being executed there in the parameter. ​ ​//The item is a callback function $("#btn_1").click(function() { alert("Btn 1 Clicked"); }); the anonymous function will be called later inside the function body. Even without a name, it can still be accessed later via the arguments object by the containing function.

Callback functions - Multiple Callback Functions Allowed

We can pass more than one callback functions into the parameter of a function, just like we can pass more than one variable. Here is a classic example with jQuery's AJAX function: function successCallback() { // Do stuff before send​ } ​ ​function successCallback() { // Do stuff if success message received​ } ​ ​function completeCallback() { // Do stuff upon completion​ } ​ ​function errorCallback() { // Do stuff if error received​ } ​ $.ajax({ url:"http://fiddle.jshell.net/favicon.png", success:successCallback, complete:completeCallback, error:errorCallback ​ });

using _ in front of JS keys

We prepended the property names with underscores (_). Developers use an underscore before a property name to indicate a property or value should not be modified directly by other code. We recommend prepending all properties with an underscore, and creating setters for all attributes you want to access later in your code.

Data in the event object

When an event is triggered, we have access to a special object called the event object. Inside of this object we can access quite a few useful values. The event object itself is quite large, but here are two of its most important parts: event.target - the target element of the event event.preventDefault() - a function that prevents the default action. This is used commonly to stop a form submission from refreshing the page (which is the default action of a submit event). You don't need to worry too much about this right now. To see just how large the event object is, save this HTML to a file, open it up in Chrome, and take a look in the console after clicking on the container: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script> document.addEventListener("DOMContentLoaded", function(){ var container = document.getElementById("container"); container.addEventListener("click", function(event){ console.log("Let's look at the event object!", event); }); }); </script> </head> <body> <div id="container"> Click on me! </div> </body> </html>

Callback functions - Problem When Using Methods With The this Object as Callbacks

When the callback function is a method that uses the this object, we have to modify how we execute the callback function to preserve the this object context. Or else the this object will either point to the global window object (in the browser), if callback was passed to a global function. Or it will point to the object of the containing method. Let's explore this in code: // Define an object with some properties and a method​ ​// We will later pass the method as a callback function to another function​ ​var clientData = { id: 094545, fullName: "Not Set", // setUserName is a method on the clientData object​ setUserName: function (firstName, lastName) { // this refers to the fullName property in this object​ this.fullName = firstName + " " + lastName; } } ​ ​function getUserInput(firstName, lastName, callback) { // Do other stuff to validate firstName/lastName here​ ​ // Now save the names​ callback (firstName, lastName); } In the following code example, when clientData.setUserName is executed, this.fullName will not set the fullName property on the clientData object. Instead, it will set fullName on the window object, since getUserInput is a global function. This happens because the this object in the global function points to the window object. getUserInput ("Barack", "Obama", clientData.setUserName); ​ console.log (clientData.fullName);// Not Set​ ​ ​// The fullName property was initialized on the window object​ console.log (window.fullName); // Barack Obama

Understanding 'this' keyword

When wanting to reference a key/value from a method you will not be able to because it will be out of scope... If you're in a method within that object it wont be able to reach it. To workaround this we use 'this'. this.hasDineInSpecial inside the object is the same as accessing restaurant.hasDineInSpecial outside the object. this will be scoped to whatever object it is within when called

Another reason why callbacks are such a powerful tool is that they enable us to manage ______ code, or code that will be executed at a later point in time.

asynchronous code How JS manages asynchronous code: call stack, event que, and heap

the function that is being passed to a higher order function and that callback function will be invoked within the higher order function

callback function

Basic Principles when Implementing Callback Functions

callback functions have a few noteworthy principles we should be familiar with when implementing them: - Use Named OR Anonymous Functions as Callbacks - Pass Parameters to Callback Functions - Make Sure Callback is a Function Before Executing It - Problem When Using Methods With The this Object as Callbacks - Use the Call or Apply Function To Preserve this - Multiple Callback Functions Allowed

Callback functions are

closures When we pass a callback function as an argument to another function, the callback is executed at some point inside the containing function's body just as if the callback were defined in the containing function. This means the callback is a closure. As we know, closures have access to the containing function's scope, so the callback function can access the containing functions' variables, and even the variables from the global scope.

There are many use cases for closures. One of the more common ones is to create a "private variable," or a variable that can not be accessed directly (and overwritten). Here's an example that uses closure to create a "private" variable.

function defineAge(){ var age = 28; return function growUp(){ return ++age; } } var ageOnce = defineAge(); ageOnce(); // 29 ageOnce(); // 30

Every single time that a function is called, we get access to a special keyword called arguments which looks like an array (it is not EXACTLY an array, but we will cover the reason why a bit later) and can be accessed using [] notation. Here is an example:

function logAll(){ console.log(arguments); } logAll(2,2); // [2,2] logAll(10,5,4); // [10,5,4] logAll(1); // [1] function displayFirstArgument(){ return arguments[0]; } displayFirstArgument(10,20); // [10] displayFirstArgument(true); // [true] displayFirstArgument(); // [] even though the arguments keyword looks like an array and even has a length property, it is actually not an array. It is a special kind of object. Manipulating this arguments array-like object can be useful, for instance, when you don't know how many arguments someone will pass in to your function: function add() { var total = 0; for (var i = 0; i < arguments.length; i++) { total += arguments[i]; // this is shorthand for total = total + arguments[i] } return total; } add(1,2,3); // 6 add(1,-2,3,-4); // -2 add(); // 0

Accessing the value of whatever is clicked When we listen for events, we sometimes want to know exactly what element triggered the event. We can do this using the _____ property on the event object, which is given to us when we use addEventListener

target property <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <ul> Ingredients <li>Sugar</li> <li>Milk</li> <li>Eggs</li> <li>Flour</li> <li>Baking Soda</li> </ul> </body> </html>; Let's access each value using the event.target property! var listItems = document.querySelectorAll('li'); for(var i=0; i<listItems.length; i++){ listItems[i].addEventListener("click", function(event){ alert("You just clicked on " + event.target.innerText); }); }

inheriting a class, aka using a parent class

use the extend keyword and super() The extends keyword makes the methods of the animal class available inside the cat class. When we call extends in a class declaration, all of the parent methods are available to the child class. The super keyword calls the constructor of the parent class. In this case, super(name) passes the name argument of the Cat class to the constructor of the Animal class. instead of making separate classes for cats and dogs. First make a Animals class then have them inherit all similar features class Animal { constructor(name) { this._name = name; this._behavior = 0; } get name() { return this._name; } get behavior() { return this._behavior; } incrementBehavior() { this._behavior++; } } now _________________________________________________________ class Cat extends Animal { constructor(name, usesLitter) { super(name); this._usesLitter = usesLitter; } }

Appending elements

var button = document.createElement("button"); button.innerText = "I am a button created with JavaScript!"; var container = document.getElementById("container"); container.appendChild(button);

Removing elements

var linkToBeRemoved = document.querySelector("a"); var container = document.getElementById("container"); container.removeChild(linkToBeRemoved);

Creating elements

var newDiv = document.createElement("div");

Capturing vs Bubbling

we have seen the addEventListener function take in two parameters: the name of the event and a callback function. But there is actually a third parameter we can pass in as a boolean called useCapture which determines if we use capturing or bubbling. Event bubbling and capturing are two ways of propagating events that occur in an element that is nested within another element, when both elements have registered a handle for that event. The event propagation mode determines the order in which elements receive the event. It's very rare that you'll need to pass in this third parameter.

!, || and &&

! - the not operator, which flips the boolean value (!true === false). !! simply applies this operator twice, so !!true === true, and !!false === false. || - the or operator, which in a boolean context returns true if either condition is true && - the and operator, which in a boolean context returns true if both conditions are true

Converting to a boolean

!! !! will convert a value to its boolean equivalent. Here are a couple of examples: var greeting = "hi"; var nothing = 0; !!greeting; // true !!nothing; // false

RangeError

occurs when we have a function that calls itself (also known as a recursive function). If we have too many functions that have been called (before they are returned) we run out of memory and cause a RangeError. function callMe(){ callMe(); } callMe(); // maximum call stack size exceeded. We will talk more about the call stack and recursion in a later section.

SyntaxError

occurs when we make a mistake with our syntax: var x = "hello"; var wrongObj = { name: "foo" missingComma: true };

ReferenceError

occurs when we try to access a variable that does not exist in that scope. In the example below, we will try to access a variable called amazing which has not yet been initialized. We will then try to access a variable called secret outside of its scope. Let's see what that looks like: amazing; // ReferenceError - does not exist in the global scope function defineSomething(){ var secret = "I'll never tell"; } defineSomething(); secret; // ReferenceError - only exists in the scope of the defineSomething function

for loop

consists of three parts followed by a block of code inside of curly braces {}: for (initializer; condition; counter) {} initializer - this is where we can declare variables to be used in the loop. We usually declare a variable called i which will serve as a counter variable for the number of times that we should loop. condition - this MUST be an expression that returns true or false. You can read this condition as "Keep looping as long as this condition is true." counter - this is how we change the variables initialized (typically, either by increasing or decreasing them). We commonly increment variables by 1 using the ++ operator and decrement by 1 using --. As long as the condition is true, the code inside the curly braces will run

in a JavaScript program occurs for one of two main reasons:

either the code that is written is not valid JavaScript code, or the code is valid, but it is trying to do something that is not allowed.

All errors in JavaScript are actually objects that are created by a function called Error

error objects are thrown when runtime errors occur. The Error object can also be used as a base object for user-defined exceptions. A runtime error is an error that occurs when code is executed. For example, if you hop into the Chrome console and write some invalid JavaScript (e.g. var 8 = 9;), you won't actually see any errors show up until you try to run the code. JavaScript has many built-in errors, which we'll talk about in just a moment. But you can also create and throw your own errors in applications that you write (this is what is meant by a "user-defined exception")

Every key in a JS object is a string

even without quotes around it. Note: You can't access a number with dot notation, need to use bracket notation. right: idToName["754"]; // returns "Tim" wrong: idToName.754; // causes an error

To figure out if all values in an array returns true to the condition

every(function(val){}); var arr = [1,2,3,4]; var everythingGreaterThanTwo = arr.every(function(val){ return val > 2; }); var everythingLessThanFive = arr.every(function(val){ return val < 5; }); everythingGreaterThanTwo; // false everythingLessThanFive; // true

With our try/catch block, we saw that the code in the try block will move to the catch block if an error occurs inside of it. In our try/catch statements, we can add one more special keyword called _______. Inside of the _______ block, code will execute regardless of an error being thrown.

finally try { // let's randomly try to throw an error if(Math.random() >= .5){ // The following code will throw: // Uncaught TypeError: undefined is not a function(...) undefined(); } console.log("Whew, we made it"); } catch(e){ console.log("We didn't make it. The error message is", e.message); } finally { console.log("No matter what we will see this statement"); }

an iterator used to take an array and reduce it to a single value

reduce() - take 4 arguments in its callback. last three arguments are value, index, array but the first is special. - Often called accumulator, the first argument value is the value of what was returned in the previous iteration. For the first iteration the value comes form the second parameter. If no argument is in the second parameter reduce will assume its the first value in the array. var arr = [2,4,6,8]; arr.reduce(function(acc,next){ return acc + next; },5); /* In the first iteration, acc is 5 and next is 2; the callback returns 5 + 2 = 7. In the second iteration, acc is 7 and next is 4; the callback returns 7 + 4 = 11. In the third iteration, acc is 11 and next is 6; the callback returns 11 + 6 = 17. In the last iteration, acc is 17 and next is 8; the callback returns 17 + 8 = 25. Now the array is exhausted, so reduce returns 25 (which is the sum of all elements in the array, plus 5) */ var arr = [2,4,6,8]; arr.reduce(function(acc,next){ return acc + next; }); // 20 (When no second argument is supplied to reduce, the `acc` starts at the first value in the array, i.e. 2. In this case, we simply get the sum of all values in the array.)

This keyword can ONLY be used inside of a function.

return - this can also be executed once in a function.

One common use case for immediately invoked function expressions is to

return an object

Method to turn a string into an array

split() allows you to manipulate a string. split by characters: var string = "hello world"; string.split(""); // ["h", "e", "l", "l", "o", " ", "w", "o", "r", "l", "d"] split by word: var string = "hello world"; string.split(" "); // ["hello", "world"]

JavaScript has 6 primitive data types, but we'll only talk about 5 of them. Here's what they look like:

string - var greeting = "hello"; number - var favoriteNum = 33; boolean - var isAwesome = true; undefined - var foo; or var setToUndefined = undefined; null - var empty = null;

when to use the throw keyword

when developing applications or libraries, we sometimes want to throw an error when something is done incorrectly in our application. To return an error and stop code execution, we use the throw keyword followed by an error object. Optionally, we can add a message string to the error to give more details about what went wrong. throw ReferenceError("That variable does not exist!"); Another way to specify an error is to use the throw keyword followed by a string: throw "This will also be an error";

event loop

JavaScript internally has something called the "Event Loop", which checks the queue and sees if there are any processes to execute. Let's examine the event loop in action: console.log("first"); setTimeout(function(){ console.log("second"); },0); console.log("third"); When we run this code, we would expect it to log out "first", "second" and "third", but that's not what happens! It logs "first", "third", "second." Here's what happens: the first log function goes on the stack, prints out "first," and then it goes off, a message is sent to the queue to log "second" in 0 milliseconds during that time, another log function comes on the stack and prints out "third" now the stack is clear so the callback to the setTimeout goes on the stack and "second" is printed

When an error is thrown, our code stops executing. Sometimes we don't know if our code is going to throw an error or not, so instead of our code crashing and not continuing to run, we might want to gracefully handle our errors.

We call this "catching" our errors. To do this we use a try / catch statement. We place code inside of the try block (a block is defined as code inside of a {}) and if an error is thrown, the code moves to the catch block. After the catch block, code continues to execute. try { thisDoesNotExist; } catch(e) { console.log("The error is ", e); }

fundamental process of JS is that it is single threaded

What this means is that only one process will happen at a time. This is unlike other languages where you can create your own threads, a process called multi-threading. However, we can write asynchronous code, which may give the impression that multiple things are happening at once, even though this is not the case.

event que

When an asynchronous event occurs, it gets put into what is called the "event queue" (also known as the queue). It is then moved to the stack when the stack is clear (i.e. when there are no functions on the stack). MDN defines the queue as "a list of messages to be processed. A function is associated with each message. When the stack is empty, a message is taken out of the queue and processed. The processing consists of calling the associated function (and thus creating an initial stack frame). The message processing ends when the stack becomes empty again." The queue is a FIFO data structure (first-in-first-out).

When you use the prompt function

a pop-up window will appear on the page and ask the user to fill in a text box. You can then store what the user types into a variable.

Comments

You can create single-line comments with //; if you want a multiline comment its /* /* this is the start of a multiline comment, and this is the ending. */

Use dot notation to access values unless

You need to use bracket notation when: - values are an expression - a variable is passed in to get the name of the key - a number is the key -singleKey is being used var obj = {}; var person = "Tom"; obj[person] = "This is a person"; obj[1+1+1] = "Three"; obj; /* obj now should look like this: { Tom: "This is a person", 3: "Three" } */ obj.3;// Syntax Error! Can't use the dot notation obj[3]; // "Three" - we NEED to use the bracket notation obj[person]; // "This is a person" obj["Tom"]; // "This is a person" obj.person; // undefined

another way to write an if / else statement is

ternary operator var guess = prompt("Guess what number I'm thinking of!"); // here's our first ternary guess === "7" ? console.log("Correct!") : console.log("Incorrect!"); expression ? pathIfTrue : pathIfFalse You can also store the value of a ternary in a variable: var num = 3; var comparison = num > 0 ? "Greater than 0" : "Less than or equal to 0"; comparison; // this will equal "Greater than 0", since 3 > 0.

In JavaScript, we have a keyword called typeof that returns

the type of the variable. typeof ""; - "string" typeof 5; - "number" typeof false; - "boolean" typeof Symbol(); - "symbol" typeof undefined; - "undefined" typeof null; // hmmm, this is not what we expect, it returns "object"!

Importance of Boolean Logic

An essential part of writing programs is being able to execute code that depends on certain conditions. There are many different examples when you'd want to conditionally execute code. Here are just a few: You want the navigation bar on your website to look different based on whether or not someone is logged in If someone enters their password incorrectly, you want to let them know; otherwise, you want to log them in You're building a tic-tac-toe game, and want to know whether it's X's turn or O's turn You're building a social network and want to keep person A from seeing person B's profile unless the two of them are friends It's very hard to write any kind of interesting software without making use of conditionals and boolean logic. make use of booleans (true and false), along with if statements and switch statements. An if statement looks something like this: var instructor = "Elie"; // we begin with an "if" statement followed by a condition in () and a block of code inside of {} if(instructor === "Elie") { console.log("Yes!"); } else { console.log("No"); }

a function which immediately gets called after it is written

An immediately invoked function expression (IIFE for short) To create an IIFE, simply wrap your anonymous function in parentheses, and then call the function: (function(){ var person = "Elie"; return person; })(); (Note: the parenthesis around the function declaration are not optional! If you don't include them, you'll get a SyntaxError. You should verify this for yourself.)

What method to use to determine if a key exists in an object?

if in var obj = { favoriteNumber: 33, favoriteColor: 'blue' } if ("favoriteNumber" in obj){ console.log("The favoriteNumber key exists!"); } // "The favoriteNumber key exists!" if ("nothing" in obj){ console.log("The nothing key exists!"); }

Method finds the first index of the element passed in

indexOf If the element is not found, it returns -1 var arr = [1,2,3,4,5,4,4]; arr.indexOf(2); // 1 arr.indexOf(3); // 2 arr.indexOf(1); // 0 - remember, arrays are zero indexed Method is commonly used to check if elements are in an array or not. var moviesIKnow = [ "Wayne's World", "The Matrix", "Anchorman", "Bridesmaids" ]; var yourFavoriteMovie = prompt("What's your favorite movie?"); if (moviesIKnow.indexOf(yourFavoriteMovie) > -1) { alert("Oh, cool, I've heard of " + yourFavoriteMovie + "!"); } else { alert("I haven't heard of " + yourFavoriteMovie + ". I'll check it out."); }

these can be used in place of for loops

iterators. JS has a number of built-methods that iterate through arrays. Makes code shorter and easier to read. forEach, map, filter, reduce

Method places elements in an array separated by argument

join var arr = ["Hello", "World"]; arr.join(" "); // "Hello World" var arr2 = ["I", "have", "a", "big", "announcement"]; arr2.join("! ") + "!"; // "I! have! a! big! announcement!"

join and split

join will bring the method back to being a string. var dashedString = "lots-of-dashes-here"; var removedDashes = dashedString.split("-").join(" "); removedDashes; // "lots of dashes here"

Method finds the last index of the element passed in

lastIndexOf like indexOf but starts at end. var arr = [1,2,3,4,5,4,4]; arr.indexOf(4); // 3 arr.lastIndexOf(4); // 6 - this one is different now as it starts from the end! arr.lastIndexOf(10); // -1 - still returns -1 if the value is not found in the array

Property that returns how many elements are in an array

length -a property not an object Note: not zero-indexed var arr = [1,2,3,4]; arr.length; // 4 arr[arr.length]; // undefined arr[arr.length-1]; // 4 - this is a nice way to access the last element of an array when you don't know how many elements are inside it.

map() key difference from forEach

map returns a new array of all the values returned in the callback. the structure of map is the same as forEach var arr = [1,2,3,4]; arr.map(function(val, index, array){ return val * 2; }); // [2,4,6,8] var tripledValues = arr.map(function(val,index,arr){ return val*3; }); tripledValues; // [3,6,9,12]

filter() key difference from map()

Inside the callback you must return an expression that evaluates to true or false. If true the value will be added to the returned array. Callback function in filter is a sort of testing function. var arr = [1,2,3,4]; var valuesGreaterThanTwo = arr.filter(function(val){ return val > 2; }); valuesGreaterThanTwo // [3,4]

what does an iteration do?

It loops through a string, array, or object

useful operator to use which returns the remainder of a number when dividing by another number

modulus operator The operator we use is %. You'll often see this operator used when checking to see if a number is even or odd. 5 % 3 === 2 // true (the remainder when five is divided by 3 is 2) var num = prompt("Please enter a whole number"); if ( num % 2 === 0 ) { console.log("the num variable is even!") } else if ( num % 2 === 1) { console.log("the num variable is odd!") } else { console.log("Hey! I asked for a whole number!"); }

Source tab for errors

more to come - int javascript

what is a multi-dimensional array?

a special kind of nested data structure, which consists of an array, each of whose elements is again an array. var myFirstSubarray = [['this','is'],['super','cool']];

New method for looping through objects

for in note: singleKey is a variable that will be assigned to each key in the object. To access the key's value we must use bracket notation. var instructor = { name: "Matt", mathWizard: true, dogOwner: true }; for(var singleKey in instructor){ console.log(instructor[singleKey]); } // the loop will log: // "Matt" // true // true

a repeatable process of procedure

function

We can also pass functions as parameters! We call functions that accept functions as parameters

higher order functions This is actually something special about JavaScript. Not all languages allow us to pass other functions as parameters to functions! // sendMessage is a higher order function as it accepts a parameter called fn. // How do we know fn is a function? We can see the fn parameter is being // invoked with () function sendMessage(message, fn){ return fn(message); } sendMessage("Hello World", console.log); // Hello World sendMessage("Hello World", alert); // Hello World is alerted sendMessage("What is your name?", prompt); // value from prompt is returned sendMessage("Do you like JavaScript?", confirm); // true or false is returned

fundamentals of the forEach iterator.

- First parameter is a callback function. - The callback function can take on three parameters: value at the current array index, current array index, and the array itself. - forEach always returns undefined. With or without the return key. - If you need to return something from your iterator, for Each is not right for you. - You don't need to use all arguments in callback. var arr = [4,3,2,1]; arr.forEach(function(val,index,arr){ console.log(val); }); // 4 // 3 // 2 // 1 arr.forEach(function(val,index,arr){ console.log(index); }); // 0 // 1 // 2 // 3 var doubledValues = arr.forEach(function(val,index,arr){ return val*2; }); doubledValues; // undefined

We can also check for inequality using:

< - less than <= - less than or equal to > - greater than >= - greater than or equal to != - not equal (loose) !== - not equal (strict)

return the first index in an array that satisfies the condition

findIndex(function(val){}); var arr = [-3,1,8,4]; var firstIndexOfElementGreaterThanTwo = arr.findIndex(function(val){ return val > 2; }); firstIndexOfElementGreaterThanTwo; // 2

Hoisting

Because variable declarations (and declarations in general) are processed before any code is executed, declaring a variable anywhere in the code is equivalent to declaring it at the top. This also means that a variable can appear to be used before it's declared. This behavior is called "hoisting", as it appears that the variable declaration is moved to the top of the function or global code.

More complex example of nested objects

Complex Objects Now let's look at an example that combines objects and arrays: var instructorData = { name: "Elie", additionalData: { instructor: true, favoriteHobbies: ["Playing Cello", "Tennis", "Coding"], moreDetails: { favoriteBasketballTeam: "New York Knicks", numberOfSiblings: 3, isYoungest: true, hometown: { city: "West Orange", state: "NJ", }, citiesLivedIn: ["Seattle", "Providence", "New York"] } } }; instructorData.name; // "Elie" instructorData.additionalData.instructor; // true instructorData.additionalData.favoriteHobbies[2]; // "Coding" instructorData.additionalData.moreDetails.favoriteBasketballTeam; // "New York Knicks" instructorData.additionalData.moreDetails.hometown.state; // "NJ" instructorData.additionalData.moreDetails.citiesLivedIn[1]; // "Providence" It is imperative that you understand how to access data in these nested data structures. If you can't get to a point where you can easily manipulate nested data structures, you'll have a very difficult time integrating any kind of outside data into the applications you'll be building later on.

Converting a value to a number

Converting to a number There are several ways you can convert a value to a number. One way is to parse the number, using parseInt or parseFloat: each function will look at a string from left to right and try to make sense of the characters it sees as numbers. Here are some examples: parseInt("2"); // 2 parseFloat("2"); // 2 parseInt("3.14"); // 3 parseFloat("3.14"); // 3.14 parseInt("2.3alkweflakwe"); // 2 parseFloat("2.3alkweflakwe"); // 2.3 parseInt("w2.3alkweflakwe"); // NaN (not a number) parseFloat("w2.3alkweflakwe"); // NaN (not a number) Both of these functions parse from left to right. If they see numbers, they'll continue parsing until they find a non-numerical character, and will either return an integer or a float, depending on which function was used. That's why parseInt("2.3alkweflakwe") returns a valid integer, but parseInt("w2.3alkweflakwe") does not. Somewhat related is the Number function. This doesn't parse, it simply tries to convert the entire string directly to a number. Sometimes this can lead to slightly different behavior compared to the parsing functions: Number("2"); // 2 Number("3.14"); // 3.14 Number("2.3alkweflakwe"); // NaN Number("w2.3alkweflakwe"); // NaN A nice shorthand for this conversion is the unary operator +: +"2"; // 2 +"3.14"; // 3.14 +"2.3alkweflakwe"; // NaN +"w2.3alkweflakwe"; // NaN

This will log out Hello! after one second. The second parameter to setTimeout controls how many milliseconds JavaScript should wait before executing the callback function.

If we pass this value in to the clearTimeout or clearInterval method, we can stop our timer! var timerId = setTimeout(function(){ console.log("Hello!"); },1000); clearTimeout(timerId); you should see that nothing gets logged to the console, because the timer id is cleared before one second has elapsed

Creating a loop inside a loop for multi-dimensional arrays

If you want to print out each individual value and not just each array you need a loop within the loop. We traditionally initialize the inner counter as j (the letter that comes after i) and we will loop as long as j is less than the length of each inner array. var nestedArr = [[1,2], [3,4]]; for(var i=0; i<nestedArr.length; i++){ for(var j=0; j<nestedArr[i].length; j++){ // notice that we are going inside the outer array // and now inside of the inner array console.log(nestedArr[i][j]); } } // this will log out... // 1 // 2 // 3 // 4

The first is a function declaration: function declaredFunction(){ return "I am a function declaration!"; } The second is a function expression: var expression = function(){ return "I am a function expression!"; }; So what is the difference between these two?

One difference is that when we use a function expression, we do not assign a "name" to the function. A function's name is the string of characters that come in between the function keyword and the set of parentheses (). The first function has a name, declaredFunction, but the second function, a function expression, does not have a name. The function without a name is called an anonymous function. The second difference is a little more subtle. It has to do with how a variable gets created in your program. We will talk about the second difference in much more detail in the next chapter.

A powerful array method for adding and removing

Splice - can think of as push, pop, unshift and shift. Takes two arguments, the starting index, which indicates where values will be removed or added, and the number of values to remove. You can also add an unlimited number of additional arguments of values you would like to add to the array. var arr = [1,2,3,4]; arr.splice(0,1); // returns [1] arr; // [2,3,4] var arr = [1,2,3,4]; arr.splice(0,1,5); // returns [1] arr; // [5,2,3,4] var arr = ["a","b","c","d"]; arr.splice(1,2,"x","y","z"); // ["b", "c"] arr; // ["a", "x", "y", "z", "d"]

four common errors we encounter when writing JavaScript

SyntaxError - occurs when we make a mistake with our syntax. ReferenceError - occurs when we try to access a variable that does not exist in that scope. TypeError - occurs when you make incorrect use of certain types in javascript. That could mean trying to invoke something that is not a function, or accessing properties on undefined. RangeError - occurs when we have a function that calls itself (also known as a recursive function). If we have too many functions that have been called (before they are returned) we run out of memory and cause a RangeError. Recursion - more to come on this one!

(before ES2015, which is where we will start), there are only 2 kinds of scope: global scope and function scope

The important takeaways here are all variables that are defined outside of functions (and inside of functions without the var keyword) are declared in the global scope, and all variables defined inside of functions can only be accessed by those functions (and any inner functions). var globalVariable = "I live in the global scope"; function makeNewScope(){ var functionScopeVariable = "I live in the scope of the makeNewScope function"; } globalVariable; // "I live in the global scope"; makeNewScope(); // maybe this will define the functionScopeVariable... functionScopeVariable; // This gives us an error! To be specific, a ReferenceError because the functionScopeVariable is not defined.

setTimeout(function(){ console.log("Hello!"); },1000); this will log ____ in ____ seconds?

This will log out Hello! after one second. The second parameter to setTimeout controls how many milliseconds JavaScript should wait before executing the callback function.

How to code an Array

Use [ ] brackets and comma to separate. Note: Arrays are Zero-Indexed

Method to figure out if any value in an array returns true to the condition

Use the some method which takes an argument and a callback and compares it to an array. arr.some(callback[, thisArg]) var array = [1, 2, 3, 4, 5]; var even = function(element) { // checks whether an element is even return element % 2 === 0; }; console.log(array.some(even)); // expected output: true

you have you use bracket notation with nested objects when

Using the dot notation is a great way to access values in nested objects. However, when dynamically setting values in a nested object (when you don't know exactly what the name of the key is going to be), you have to use the bracket notation. Let's take a look at a quick example. In the example below, we'd like to write a function that adds a key to the nested object var programmingLanguages = { java: { yearCreated: 1995, creator: "James Gosling" }, javaScript: { yearCreated: 1995, creator: "Brendan Eich" } } function addProgrammingLanguage(nameOfLanguage, yearLanguageCreated, creatorOfLanguage){ // how can we access the programming languages object? // We can't use dot notation, because we don't know the name of // the key until the function is called. // Instead we use bracket notation where the key is the // nameOfLanguage that is being passed to the function. programmingLanguages[nameOfLanguage] = { // Creating the object which will be the value of the // key. We can directly assign the yearLanguageCreated // and creatorOfLanguage to the appropriate keys here. yearCreated: yearLanguageCreated, creator: creatorOfLanguage } } // Usage example: Adding a key of ruby to the programming language object, // with the value of 1995 for the key "yearCreated" and the value // "Yukihiro Matsumoto" for creatorOfLanguage addProgrammingLanguage("ruby", 1995, "Yukihiro Matsumoto");

when programming in JavaScript, you will see anonymous functions being passed as parameters very often

We can even pass an anonymous function as a parameter! sendMessage("Hello World", function(message){ // message refers to the string "Hello World" console.log(message + " from a callback function!"); }); // Hello World from a callback function! The previous example is equivalent to doing the following: var myFunction = function(message){ // message refers to the string "Hello World" console.log(message + " from a callback function!"); }; sendMessage("Hello World", myFunction);

Another way to write conditional logic is to use a switch statement

While these are used less frequently, they can be quite useful when there are multiple conditions that can be met. Notice that each case clause needs to end with a break so that we exit the switch statement. Here is an example: var feeling = prompt("How are you feeling today?").toLowerCase(); // what do you think the .toLowerCase does at the end? switch(feeling){ case "happy": console.log("Awesome, I'm feeling happy too!"); break; case "sad": console.log("That's too bad, I hope you feel better soon."); break; case "hungry": console.log("Me too, let's go eat some pizza!"); break; default: console.log("I see. Thanks for sharing!"); }

Multidimensional

are a special kind of nested data structure, which consists of an array, each of whose elements is again an array Here's an example: var myFirstSubarray = [['this','is'],['super','cool']]; if you want to print out all of the values of a multidimensional array you are going to need a loop inside of a loop! var nestedArr = [[1,2], [3,4]]; for(var i=0; i<nestedArr.length; i++){ console.log(nestedArr[i]); } // this will log out... // [1,2] // [3,4] What if you want to print out each individual value? We will need another loop inside of the first loop. We traditionally initialize the inner counter as j (the letter that comes after i) and we will loop as long as j is less than the length of each inner array. var nestedArr = [[1,2], [3,4]]; for(var i=0; i<nestedArr.length; i++){ for(var j=0; j<nestedArr[i].length; j++){ // notice that we are going inside the outer array // and now inside of the inner array console.log(nestedArr[i][j]); } } // this will log out... // 1 // 2 // 3 // 4

Skip the current iteration and contue the loop at the next step

continue

removing a key from an object

delete keyword var obj = { name: "Elie", job: "Instructor" }; delete obj.job; // returns true obj; /* { name: "Elie" } */

adding properties or functions to an object

dot is preferred but not always possible. var obj = { name: "Jon Snow", watchMember: true }; obj.gameOfThrones = "awesome"; obj; /* { name: "Jon Snow", watchMember: true, gameOfThrones: "awesome" } */

How to access object values

dot notation firstObj.firstName; // returns "Tim" bracket notation firstObj["firstName"]; // returns "Tim"

return the first element in an array that satisfies the condition

find(function(val){}); var arr = [-3,1,8,4]; var firstValueGreaterThanTwo = arr.find(function(val){ return val > 2; }); firstValueGreaterThanTwo; // 8

TypeError

occurs when you make incorrect use of certain types in javascript. That could mean trying to invoke something that is not a function, or accessing properties on undefined. Here are some very common examples (many of them we guarantee you will make!) undefined(); // TypeError - undefined is NOT a function! var obj = { name: "Elie" }; obj.something; // this actually returns undefined! What does that tell us? If you try to access a property on an object and it does not exist, you do NOT get a ReferenceError, you just get undefined obj.something.foo; // but when you try to access a property on `undefined`... well, that's a TypeError. obj.something(); this is a TypeError for the same reason that undefined() is, since obj.something is undefined!

nested data structure

one data structure inside of another Simple Example of objects within objects: var schools = { georgiaInstituteOfTechnology: { address: "North Ave NW, Atlanta, GA 30332", phoneNumber: "(404) 894-2000", dateEstablished: "October 13, 1885" } }; Now to access an object within an object, we can use dot notation just like in objects that are not nested: // This statement assigns the object that is nested inside // of the larger schools object to the gtObject variable. var gtObject = schools.georgiaInstituteOfTechnology; Now that we have the gtObject variable, we can use it to access keys within that object: gtObject.address; // returns "North Ave NW, Atlanta, GA 30332" gtObject.phoneNumber; // returns "(404) 894-2000" gtObject.dateEstablished; //returns "October 13, 1885" Ex of arrays within objects: var instructorData = { name: "Tim", favoriteHobbies: ["Sailing", "Hiking", "Coding"] }; To get the first element in the array, the code would be as follows: instructorData.favoriteHobbies[0]; // returns "Sailing"

Inputs to a function are called

parameters or arguments

Using the split() method to remove from an array

pass a delimiter into the split method, the delimiting values will be removed from the array var dashedString = "lots-of-dashes-here"; var removedDashes = dashedString.split("-"); removedDashes; // ["lots", "of", "dashes", "here"]

Adding and removing from an array

push to end, unshift a new beginning, pop off the end, and shift off the first. var arr = [3, 2, 5]; arr.push(7); // returns the new length, i.e. 4 arr; // [3, 2, 5, 7] arr.unshift(0); // returns the new length, i.e. 5 arr; // [0,3,2,5,7] arr.pop(); // returns 4 arr; // [0,3,2,5] arr.shift(); // returns 3 arr; // [3,2,5]

It's quite common to write code that we want to be executed after a specific amount of time. Maybe you want to put a timer in a game, or perform some animation on the page after a fixed amount of time has elapsed. To do this, we use the

setTimeout and setInterval functions. Both functions accept a callback function and a time in milliseconds as parameters. The main difference is that the setTimeout function will only run the callback function to be executed once, whereas setInterval will run it an infinite amount of times (until the timer is cleared).

Writing functions to produce values in a nested data structure

sometimes it's helpful to encapsulate some of your logic into a function. This is especially true if you'll need to manipulate the data structure in similar ways multiple times. ex: var instructorData = { name: "Elie", additionalData: { instructor: true, favoriteHobbies: ["Playing Cello", "Tennis", "Coding"], moreDetails: { favoriteBasketballTeam: "New York Knicks", numberOfSiblings: 3, isYoungest: true, hometown: { city: "West Orange", state: "NJ", }, citiesLivedIn: ["Seattle", "Providence", "New York"] } } }; function to display cities: function displayCities(){ var cityArray = instructorData.additionalData.moreDetails.citiesLivedIn; for(var i=0; i< cityArray.length; i++){ console.log(cityArray[i]); } }

A real world analogy of a function

the brew button on a coffee machine. The coffee machine has inputs (hot water, and coffee grounds), and outputs (hot coffee). When you press the button to brew a pot of coffee, you are starting a process that should return an expected output to you. The same thing is true in programming. A function takes a set of variables as inputs and returns a value as an output.

why would you want to combine iterators?

to manipulate arrays by combining a sequence of simple functions. var arr = [1,2,3,4,5] arr.filter(function(val){ return val % 2 !== 0; // only keep odd numbers }).map(function(val){ return val * 2; // double remaining values }).reduce(function(acc,next){ return acc + next; // add everything up },0) // 18 chaining helps keep code easy to reason about because each callback is responsible for one thing. To make even more readable, give names to the callbacks. var arr = [1,2,3,4,5]; function isNumberOdd(val) { return val % 2 === 1; } function doubleValue(val) { return val * 2; } function sum(a,b) { return a + b; } arr.filter(isNumberOdd) .map(doubleValue) .reduce(sum,0); // 18

exit a loop before its finished

use a break for(var i = 0; i<5; i++){ if(Math.random() > 0.5){ console.log("Breaking out of the loop when i is " + i); break; } else { console.log(i); } }

How to update an array value

var arr = [5,3,10]; arr[0]; // should equal 5 arr[0] = -1000; arr[2] = "dope"; arr; // should be [-1000, 3, "dope"]

while and do...while

var i = 0; while(i < 5){ console.log(i); i++; } var i = 0; do { console.log(i); i++; } while(i < 5) Main difference is do..while is garenteed to run once.

Sometimes you need more than two conditions to check. In this case, you can chain together multiple conditions using else if

var number = prompt("What's your favorite number?"); if (number >= 1000) { console.log("Woah, that's a big number!"); } else if (number >= 0) { console.log("That's a cool number."); } else { console.log("Negative numbers?! That's just bananas."); }

closure

when a function is able to access variables from an outer function that has already returned. Thanks to JavaScript's inner workings, a function is able to remember variables defined in functions even if that function has returned. Let's see what we mean by that with an example. function outer(a){ return function inner(b){ return a + b; } } outer(5) // this returns the inner function // this calls the inner function right away outer(5)(2) // 7 // we can store the inner function in a variable var laterAdd = outer(10) // we can now call that inner function laterAdd(15) // 25 // but how was the inner function able to remember the parameter "a" defined in the outer function which already returned? The answer is through closure.

call stack

where function calls are put (each one is called a "stack frame"). The call stack (sometimes simply referred to as the stack) is a LIFO (last-in-first-out) data structure. You can think of the stack like a stack of cups (last one you put on the stack is the first one that comes off). What that means is that if there is a function on the stack and it is under another function, it can never execute until the function on top has come off the stack (either by returning some value or by executing all the code in the function).


Ensembles d'études connexes

Series 6: Retirement Plans (Retirement Plan Types and Features)

View Set

Basic Livestock Surgical Procedures

View Set

Szülésznő tesztsor 401-500 (I. Egyszerű feleletválasztás)

View Set

Chapter: Chapter 14: Implementing

View Set

Quiz 6: Marketing Information and Research

View Set