Table of Contents
What is JavaScript
- Every browser as has built-in JavaScript Engines
- JavaScript Console (openable via Chrome)
- Add styles and animations to JavaScript Console (see code example)
document.body.addEventListener('click', function () {
const myParent = document.getElementsByTagName("h1")[0];
const myImage = document.createElement("img");
myImage.src = 'https://thecatapi.com/api/images/get?format=src&type=gif';
myParent.appendChild(myImage);
myImage.style.marginLeft = "160px";
});
Datatypes
Primitive datatypes
- numbers
- strings
- booleans
- undefined
- null
numbers
- Addition a + b Adds a and b
- Subtraction a - b Subtracts b from a
- Multiplication a * b Multiplies a and b
- Division a / b Divides a by b
- Modulo a % b Returns the remainder of a / b
- Exponent a ** b Raises a to the power of b
comments
// line comment
/* block comment
var rev;
*/
strings
TIP: It is correct to either use double " or single ' quotes with strings, as long as you're consistent. The JavaScript Udacity style guide for labs and projects suggests using single quotes to define string literals -- but your team or organization might follow a different style guide and prefer double quotes.
Special characters
\\ \ (backslash)
" '' (double quote)
' ' (single quote)
\n newline
\t tab
variables
In the example and video above, we used the keyword var to declare our variable. When we use var we create a variable that is available in the global scope -- which means it can be used anywhere in our program. We'll talk more about scope later, but for now, keep in mind that globally scoped variables are not a good practice.
Here's why: in a small program with just a few variables, it's easy to keep track of the variables and avoid collisions. But when you are working on a complex project or with a large team. It is very easy to inadvertently overwrite an existing variable that is hidden in another part of the program. let and const avoid this issue because they are only available in the scope where they are declared.
Best Practice #1
Always use let or const instead of var
Best Practice #2
If you aren't sure, use const. You can revise your code later to replace the const with let if needed.
Naming conventions
When you create a variable, you write the name of the variable using camelCase (the first word is lowercase, and all following words are uppercase). Also try to use a variable name that accurately, but succinctly describes what the data is about.
const totalAfterTax = 53.03;
Null, Undefined, and NaN
What is the Difference Between null and undefined?
null refers to the "value of nothing", while undefined refers to the "absence of value".
Conditions
Here’s the list of all of the falsy values:
- the Boolean value false
- the null type
- the undefined type
- the number 0
- the empty string ""
- the odd value NaN (stands for "not a number", check out the NaN MDN article)
Tenerary operator
conditional ? (if condition is true) : (if condition is false)
Key Points to Remember
As you face new challenges and complex problems, remember what you learned in this lesson about using logic to create algorithms:
- Break the problem down into smaller steps
- Use conditional statements and logical operators to tell your code when and how to run
Write if...else and else...if conditionals
Use logical operators to handle more complex logic
Identify truthy and falsy values
Use ternary operators for more concise conditional logic
Use a switch statement to chain multiple else if statements
Functions
Functions Are Awesome
The ability to generalize code for a variety of possible inputs is a powerful tool when creating easy to understand, non-repetitive code.
function reverseString(reverseMe) {
let reversed = "";
for (let i = reverseMe.length - 1; i >= 0; i--) {
reversed += reverseMe[i];
}
return reversed;
}
console.log(reverseString("Julia"));
Summary of functions
Functions package up code so you can easily use (and reuse) a block of code.
Parameters are variables that are used to store the data that's passed into a function for the function to use.
Arguments are the actual data that's passed into a function when it is invoked:
// x and y are parameters in this function declaration
function add(x, y) {
// function body
// Here, `sum` variable has a scope within the function.
// Such variables defined within a function are called Local variables
// You can try giving it another name
const sum = x + y;
return sum; // return statement
}
// 1 and 2 are passed into the function as arguments,
// and the result returned by the function is stored in a new variable `sum`
// Here, `sum` is another variable, different from the one used inside the function
const sum = add(1, 2);
The function body is enclosed inside curly brackets:
function add(x, y) {
// function body!
}
Return statements explicitly make your function return a value:
return sum;
You invoke or call a function to have it do something:
add(1, 2);
Returns: 3
Global and Function Scope
The Three Types of Scope in JavaScript
JavaScript has three types of scope.
- global scope
- function scope
- block scope
The first two are pretty simple:
- Variables declared in the global scope are accessible to any other part of the program.
- Variables declared inside a function are in the function scope which means they are only accessible inside that function.
How Does Javascript Find a Variable? It Uses the Scope Chain
When the JavaScript engine is looking for a variable, it starts from the current scope and moves outward:
The JavaScript engine will start looking in the scope where the variable is requested.
If it can't find it in the current scope, it moves out one level and checks again.
It keeps moving to the outer scope until it has reached the global scope.
If the JavaScript engine checks all of the outer functions and global scope, and it still can't find the identifier then it will return a Reference error.
// <-- 4. JavaScript engine looks here last
const globalVar = "I am in the global scope";
function outerOuterFunction() {
// <-- 3. JavaScript engine looks here third
const outerOuterVar = 'I am in the outerOuterFunction scope';
function outerFunction() {
// <-- 2. JavaScript engine looks here second
const outerVar = 'I am in the outerFunction scope';
function innerFunction() {
// <-- 1. JavaScript engine looks here first
const innerVar = 'I am in the innerFunction scope';
console.log(globarVar);
}
}
}
Scope Recap
- If an identifier is declared in global scope, it's available everywhere.
- If an identifier is declared in function scope, it's available in the function it was declared in (even in functions declared inside the function).
- If an identifier is declared in block scope with var, it is available in the block and in the outer scope of the block it was declared in.
- If an identifier is declared in block scope with let or const, it is only available in the block it was declared in.
- When trying to access an identifier, the JavaScript Engine will first look in the current function. If it doesn't find anything, it will continue to the next outer function to see if it can find the identifier there. It will keep doing this until it reaches the global scope.
- Global identifiers are a bad idea. They can lead to bad variable names, conflicting variable names, and messy code.
Function expression
For instance, remember how you can store anything you want in a variable? Well, in JavaScript, you can also store functions in variables. When a function is stored inside a variable it's called a function expression.
Notice how the function keyword no longer has a name.
const catSays = function(max) {
// code here
};
It's an anonymous function, a function with no name, and you've stored it in a variable called catSays.
Hoisting
JavaScript is Different!
In most programming languages, you have to declare a function or variable before you can call it.
Intuitively, you might think "This code shouldn't work!" because we're trying to call findAverage before it is declared:
findAverage(5, 9);
function findAverage(x, y) {
var answer = (x + y) / 2;
return answer;
}
But, surprisingly it does work!
Returns 7
in JavaScript we can call a function before we declare it due to hoisting. Before any JavaScript code is executed, all function declarations and variables declared with var are hoisted to the top of their current scope.
Hoisting Recap
JavaScript hoists function declarations and variables declared with var to the top of the current scope.
Hoisting doesn't happen when variables are declared with let or const.
Variable assignments are not hoisted so function expressions are not hoisted.
Best Practices
Declare functions and variables at the top of your scripts, so the syntax and behavior are consistent with each other.
Use let and const to declare variables. You may see var in legacy code, but do not use it in any new code you are writing.
Patterns with Function Expressions
Functions as Parameters
Being able to store a function in a variable makes it really simple to pass the function into another function. A function that is passed into another function is called a callback. Let's say you had a helloCat() function, and you wanted it to return "Hello" followed by a string of "meows" like you had with catSays. Well, rather than redoing all of your hard work, you can make helloCat() accept a callback function, and pass in catSays.
// function expression catSays
const catSays = function(max) {
let catMessage = "";
for (let i = 0; i < max; i++) {
catMessage += "meow ";
}
return catMessage;
};
// function declaration helloCat accepting a callback
function helloCat(callbackFunc) {
return "Hello " + callbackFunc(3);
}
// pass in catSays as a callback function
helloCat(catSays);
Returns 'Hello meow meow meow '
Inline Function Expressions
A function expression is when a function is assigned to a variable. And, in JavaScript, this can also happen when you pass a function inline as an argument to another function. Take the favoriteMovie example for instance:
// Function expression that assigns the function displayFavorite
// to the variable favoriteMovie
const favoriteMovie = function displayFavorite(movieName) {
console.log("My favorite movie is " + movieName);
};
// Function declaration that has two parameters: a function for displaying
// a message, along with a name of a movie
function movies(messageFunction, name) {
messageFunction(name);
}
// Call the movies function, pass in the favoriteMovie function and name of movie
movies(favoriteMovie, "Finding Nemo");
Returns: My favorite movie is Finding Nemo
Why Use Anonymous Inline Function Expressions?
Using an anonymous inline function expression might not seem useful at first. Why define a function that can only be used once and you can't even call it by name?
Anonymous inline function expressions are often used with function callbacks that are unlikely to be reused elsewhere. Yes, you could store the function in a variable, give it a name, and pass it in like you saw in the examples above. However, when you know the function is not going to be reused, it could save you many lines of code to just define it inline.
For example, we can make the callback function in movies an anonymous inline function like this:
function movies(messageFunction, name) {
messageFunction(name);
}
movies(function (movieName) {
console.log("My favorite movie is " + movieName);
}, "Finding Nemo");
Arrays
Creating an array
Using the Array Constructor
You may also see arrays created this way:
// creates a new empty array
const emptyArray = new Array();
// creates a `donuts` array with three strings
const donuts = new Array("glazed", "powdered", "jelly");
This syntax is valid, but it is preferred to use the literal constructor because the syntax is simpler and more intuitive.
// creates a new empty array
const emptyArray = [];
// creates a `donuts` array with three strings
const donuts = ["glazed", "powdered", "jelly"];
Accessing arrays
const donuts = [
"glazed", // index is 0
"chocolate frosted", // index is 1
"cinnamon", // index is 2
"sprinkled", // index is 3
"powdered", // index is 4
"cinnamon sugar", // index is 5
"glazed cruller", // index is 6
"chocolate cruller", // index is 7
"cookies", // index is 8
"Boston creme", // index is 9
"powdered jelly filled", // index is 10
"creme de leche", // index is 11
"glazed donut holes", // index is 12
"blueberry donut holes", // index is 13
"cake donut holes", // index is 14
"chocolate donut holes" // index is 15
];
console.log(donuts[11]); // "creme de leche"
Exkurs: Primitive vs. Object Types in JavaScript
String, Number, Boolean, undefined and null are considered Primitive Types in JavaScript. These relatively simple data types represent just one value which makes it easy for JavaScript to store that value. So when you assign a primitive value to a variable, JavaScript actually assigns that value.
Arrays are more complicated because they consist of a list of values which makes storage much more complicated. Arrays are actually Object types which means that instead of assigning all of the values of the list to the array, JavaScript simply assigns a reference to where to find the values in the array. Even if the values inside the object change, the reference address doesn't.
Here's an analogy that might help. Think of a JavaScript array as if it were a house. The house has a group of people who live inside it. If those people move out, and a new group of people moves in, the names of the people inside the house changes, but the house's postal address won't.
Best practise - Arrays const vs let?
TLDR;
We use const to declare arrays because JavaScript is assigning a reference that points to that array. We can change whatever we want inside the array, but we cannot change which array the variable points to.
Arrays are Powerful Data Structures
Arrays have a number of properties and built-in methods.
Array properties includelengthwhich is similar to the length method for String types.
Common Array methods include:
- reverse: reverses the order of the elements in an array
- sort: sorts the elements in an array
- push: adds elements to an array (on top)
- pop: removes elements from an array (from top)
- splice() method: arrayName.splice(arg1, arg2, item1, ....., itemX); where,
arg1 = Mandatory argument. Specifies the starting index position to add/remove items. You can use a negative value to specify the position from the end of the array e.g., -1 specifies the last element.
arg2 = Optional argument. Specifies the count of elements to be removed. If set to 0, no items will be removed.
item1, ....., itemX are the items to be added at index position arg1
splice() method returns the item(s) that were removed.
To see all of the properties and built-in methods for modifying arrays and accessing values in an array, check out the MDN Documentation (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)
Array Loops
const donuts = ["jelly donut", "chocolate donut", "glazed donut"];
// the variable `i` is used to step through each element in the array
for (let i = 0; i < donuts.length; i++) {
donuts[i] += " hole";
donuts[i] = donuts[i].toUpperCase();
}
The forEach Method
The forEach() method gives you an alternative way to iterate over an array, and manipulate each element in the array with an inline function expression.
const donuts = ["jelly donut", "chocolate donut", "glazed donut"];
donuts.forEach(function(donut) {
donut += " hole";
donut = donut.toUpperCase();
console.log(donut);
});
map Loops
Creating a new array from an existing array is simple with the powerful map() method.
With the map() method, you can take an array, perform some operation on each element of the array, and return a new array.
const newArray = myArray.map(function (elem) {
elem = elem + 100;
return elem;
});
console.log(newArray); //[101, 102, 103, 104, 105]
2dim arrays
for (let row = 0; row < donutBox.length; row++) {
// here, donutBox[row].length refers to the length of the donut array currently being looped over
for (let column = 0; column < donutBox[row].length; column++) {
console.log(donutBox[row][column]);
}
}