- Introduction
- var let const
- Comparison operator
- Truthy and Falsy
- Ternary Operator
- Function and Hoisting
- Scope
- Array
- Functions as Data
- Introduction to Iterators
- The .forEach() Method
- The .map() Method
- The .filter() Method
- The .findIndex() Method
- The .reduce() Method
- Introduction to Objects
- References
JavaScript (JS) is a lightweight, interpreted, or just-in-time compiled programming language with first-class functions. While it is most well-known as the scripting language for Web pages, many non-browser environments also use it, such as Node.js, Apache CouchDB and Adobe Acrobat. JavaScript is a prototype-based, multi-paradigm, single-threaded, dynamic language, supporting object-oriented, imperative, and declarative (e.g. functional programming) styles.
JavaScript was initially created to “make web pages alive”.
The programs in this language are called scripts. They can be written right in a web page’s HTML and run automatically as the page loads.
Scripts are provided and executed as plain text. They don’t need special preparation or compilation to run.
What makes JavaScript unique?
Full integration with HTML/CSS.
Simple things are done simply.
Support by all major browsers and enabled by defaults.
var declarations are globally scoped or function scoped while let and const are block scoped.
var variables can be updated and re-declared within its scope; let variables can be updated but not re-declared; const variables can neither be updated nor re-declared.
They are all hoisted to the top of their scope. But while var variables are initialized with undefined, let and const variables are not initialized.
While var and let can be declared without being initialized, const must be initialized during declaration.
Variables that have not been initialized store the primitive data type undefined.
In ES6, template literals use backticks ` and ${} to interpolate values into a string.
const myPet = 'armadillo';
console.log(`I own a pet ${myPet}.`);
// Output: I own a pet armadillo.
The typeof keyword returns the data type (as a string) of a value.
const unknown1 = 'foo';
console.log(typeof unknown1); // Output: string
const unknown2 = 10;
console.log(typeof unknown2); // Output: number
const unknown3 = true;
console.log(typeof unknown3); // Output: boolean
if (stopLight === 'green' && pedestrians === 0) {
console.log('Go!');
} else {
console.log('Stop');
}
So which values are falsy— or evaluate to false when checked as a condition? The list of falsy values includes:
0
Empty strings like "" or ''
null which represent when there is no value at all
undefined which represent when a declared variable lacks a value
NaN, or Not a Number
let numberOfApples = 0;
if (numberOfApples){
console.log('Let us eat apples!');
} else {
console.log('No apples left!');
}
// Prints 'No apples left!'
Truthy and falsy evaluations open a world of short-hand possibilities!
Say you have a website and want to take a user’s username to make a personalized greeting. Sometimes, the user does not have an account, making the username variable falsy. The code below checks if username is defined and assigns a default string if it is not:
let defaultName;
if (username) {
defaultName = username;
} else {
defaultName = 'Stranger';
}
If you combine your knowledge of logical operators you can use a short-hand for the code above. In a boolean condition, JavaScript assigns the truthy value to a variable if you use the || operator in your assignment:
let defaultName = username || 'Stranger';
Because || or statements check the left-hand condition first, the variable defaultName will be assigned the actual value of username if is truthy, and it will be assigned the value of 'Stranger' if username is falsy. This concept is also referred to as short-circuit evaluation.
In the spirit of using short-hand syntax, we can use a ternary operator to simplify an if...else statement.
Comparison operators, including <, >, <=, >=, ===, and !== can compare two values.
Take a look at the if...else statement example:
let isNightTime = true;
if (isNightTime) {
console.log('Turn on the lights!');
} else {
console.log('Turn off the lights!');
}
We can use a ternary operator to perform the same functionality:
isNightTime ? console.log('Turn on the lights!') : console.log('Turn off the lights!');
A function declaration consists of:
The function keyword.
The name of the function, or its identifier, followed by parentheses.
A function body, or the block of statements required to perform a specific task, enclosed in the function’s curly brackets, { }.
console.log(greetWorld()); // Output: Hello, World!
function greetWorld() {
console.log('Hello, World!');
}
Hoisting
Hoisting is a term you will not find used in any normative specification prose prior to ECMAScript® 2015 Language Specification.
One of the advantages of JavaScript putting function declarations into memory before it executes any code segment is that it allows you to use a function before you declare it in your code. For example:
function catName(name) {
console.log("My cat's name is " + name);
}
catName("Tiger");
/*
The result of the code above is: "My cat's name is Tiger"
*/
The above code snippet is how you would expect to write the code for it to work. Now, let's see what happens when we call the function before we write it:
catName("Chloe");
function catName(name) {
console.log("My cat's name is " + name);
}
/*
The result of the code above is: "My cat's name is Chloe"
*/
Even though we call the function in our code first, before the function is written, the code still works. This is because of how context execution works in JavaScript.
Hoisting works well with other data types and variables. The variables can be initialized and used before they are declared.
JavaScript only hoists declarations, not initializations. If a variable is declared and initialized after using it, the value will be undefined.
Another way to define a function is to use a function expression.
To define a function inside an expression, we can use the function keyword.
In a function expression, the function name is usually omitted.
A function with no name is called an anonymous function.
A function expression is often stored in a variable in order to refer to it.
Unlike function declarations, function expressions are not hoisted so they cannot be called before they are defined.
To declare a function expression:
Declare a variable to make the variable’s name be the name, or identifier, of your function. Since the release of ES6, it is common practice to use const as the keyword to declare the variable.
Assign as that variable’s value an anonymous function created by using the function keyword followed by a set of parentheses with possible parameters. Then a set of curly braces that contain the function body.
const plantNeedsWater = function(day){
if(day === 'Wednesday')
return true;
else
return false;
}
console.log(plantNeedsWater('Tuesday'));
ES6 introduced arrow function syntax, a shorter way to write functions by using the special “fat arrow” () => notation.
Arrow functions remove the need to type out the keyword function every time you need to create a function.
Instead, you first include the parameters inside the ( ) and then add an arrow => that points to the function body surrounded in { } like this:
const rectangleArea = (width, height) => {
let area = width * height;
return area;
};
JavaScript also provides several ways to refactor arrow function syntax.
The most condensed form of the function is known as concise body. We’ll explore a few of these techniques below:
Functions that take only a single parameter do not need that parameter to be enclosed in parentheses. However, if a function takes zero or multiple parameters, parentheses are required.
ZERO PARAMETERS
cost fucntionName = () => {};
ONE PARAMETER
const functionName = paraOne => {};
TWO OR MORE PARAMETERS
const functionName = (paramOne, paramTwo) => {};
A function body composed of a single-line block does not need curly braces. Without the curly braces, whatever that line evaluates will be automatically returned. The contents of the block should immediately follow the arrow => and the return keyword can be removed. This is referred to as implicit return.
SINGLE-LINE BLOCK
const sumNumbers = numsber => number + number;
MULTI-LINE BLOCK
const sumNumbers = number => {
const sum = number + number;
return sum;
};
An important idea in programming is scope.
Scope defines where variables can be accessed or referenced.
While some variables can be accessed from anywhere within a program, other variables may only be available in a specific context.
Scope is the idea in programming that some variables are accessible/inaccessible from other parts of the program.
Blocks are statements that exist within curly braces {}.
Global scope refers to the context within which variables are accessible to every part of the program.
Global variables are variables that exist within global scope.
Block scope refers to the context within which variables that are accessible only within the block they are defined.
Local variables are variables that exist within block scope.
Global namespace is the space in our code that contains globally scoped information.
Scope pollution is when too many variables exist in a namespace or variable names are reused.
Arrays are JavaScript’s way of making lists. Arrays can store any data types (including strings, numbers, and booleans).
Like lists, arrays are ordered, meaning each item has a numbered position.
Arrays in JavaScript are zero-indexed, meaning the positions start counting from 0 rather than 1. Therefore, the first item in an array will be at position 0.
You may recall that you can declare variables with both the let and const keywords. Variables declared with let can be reassigned.
Variables declared with the const keyword cannot be reassigned.
However, elements in an array declared with const remain mutable.
Meaning that we can change the contents of a const array, but cannot reassign a new array or a different value.
One of an array’s built-in properties is length and it returns the number of items in the array.
We access the .length property just like we do with strings. Check the example below:
const newYearsResolutions = ['Keep a journal', 'Take a falconry class'];
console.log(newYearsResolutions.length);
// Output: 2
We use dot notation, chaining a period with the property name to the array, to access the length property of the newYearsResolutions array.
One method, .push() allows us to add items to the end of an array. Here is an example of how this is used:
const itemTracker = ['item 0', 'item 1', 'item 2'];
itemTracker.push('item 3', 'item 4');
console.log(itemTracker);
// Output: ['item 0', 'item 1', 'item 2', 'item 3', 'item 4'];
Notice that .push() changes, or mutates, itemTracker. You might also see .push() referred to as a destructive array method since it changes the initial array.
If you’re looking for a method that will mutate an array by adding elements to it, then .push() is the method for you!
Another array method, .pop(), removes the last item of an array.
const newItemTracker = ['item 0', 'item 1', 'item 2'];
const removed = newItemTracker.pop();
console.log(newItemTracker);
// Output: [ 'item 0', 'item 1' ]
console.log(removed);
// Output: item 2
.pop() returns the value of the last element. In the example, we store the returned value in a variable removed to be used for later.
.pop() is a method that mutates the initial array.
When you need to mutate an array by removing the last element, use .pop().
Some arrays methods that are available to JavaScript developers include: .join(), .slice(), .splice(), .shift(), .unshift(), and .concat().
JavaScript functions behave like any other data type in the language; we can assign functions to variables, and we can reassign them to new variables.
const announceThatIAmDoingImportantWork = () => {
console.log("I’m doing very important work!");
};
const busy = announceThatIAmDoingImportantWork;
busy(); // This function call barely takes any space!
busy is a variable that holds a reference to our original function.
If we could look up the address in memory of busy and the address in memory of announceThatIAmDoingImportantWork they would point to the same place.
Our new busy() function can be invoked with parentheses as if that was the name we originally gave our function.
Since functions are a type of object, they have properties such as .length and .name** and methods such as .toString().
Since functions can behave like any other type of data in JavaScript, it might not surprise you to learn that we can also pass functions (into other functions) as parameters.
A higher-order function is a function that either accepts functions as parameters, returns a function, or both!
We call the functions that get passed in as parameters and invoked callback functions because they get called during the execution of the higher-order function.
JavaScript functions are first-class objects, so they have properties and methods like any object
Functions can be passed into other functions as parameters
A higher-order function is a function that either accepts functions as parameters, returns a function, or both
The built-in JavaScript array methods that help us iterate are called iteration methods, at times referred to as iterators.
Iterators are methods called on arrays to manipulate elements and return values.
Notice the different methods being called on the arrays:
.forEach()
.map()
.filter()
const artists = ['Picasso', 'Kahlo', 'Matisse', 'Utamaro'];
artists.forEach(artist => {
console.log(artist + ' is one of my favorite artists.');
});
const numbers = [1, 2, 3, 4, 5];
const squareNumbers = numbers.map(number => {
return number * number;
});
console.log(squareNumbers);
const things = ['desk', 'chair', 5, 'backpack', 3.14, 100];
const onlyNumbers = things.filter(thing => {
return typeof thing === 'number';
});
console.log(onlyNumbers);
Output :
Picasso is one of my favorite artists.
Kahlo is one of my favorite artists.
Matisse is one of my favorite artists.
Utamaro is one of my favorite artists.
[ 1, 4, 9, 16, 25 ]
[ 5, 3.14, 100 ]
The first iteration method that we’re going to learn is .forEach(). Aptly named, .forEach() will execute the same code for each element of an array.
The code above will log a nicely formatted list of the groceries to the console. Let’s explore the syntax of invoking .forEach().
groceries.forEach() calls the forEach method on the groceries array.
.forEach() takes an argument of callback function. Remember, a callback function is a function passed as an argument into another function.
.forEach() loops through the array and executes the callback function for each element.
During each execution, the current element is passed as an argument to the callback function.
The return value for .forEach() will always be undefined.
Another way to pass a callback for .forEach() is to use arrow function syntax.
groceries.forEach(groceryItem => console.log(groceryItem));
We can also define a function beforehand to be used as the callback function.
function printGrocery(element){
console.log(element);
}
groceries.forEach(printGrocery);
All three code snippets do the same thing. In each array iteration method, we can use any of the three examples to supply a callback function as an argument to the iterator.
It’s good to be aware of the different ways to pass in callback functions as arguments in iterators because developers have different stylistic preferences.
Nonetheless, due to the strong adoption of ES6, we will be using arrow function syntax in the later exercises. 4
When .map() is called on an array, it takes an argument of a callback function and returns a new array!
Take a look at an example of calling .map():
const numbers = [1, 2, 3, 4, 5];
const bigNumbers = numbers.map(number => {
return number * 10;
});
map() works in a similar manner to .forEach()— the major difference is that .map() returns a new array.
In the example above:
numbers is an array of numbers.
bigNumbers will store the return value of calling .map() on numbers.
numbers.map will iterate through each element in the numbers array and pass the element into the callback function.
return number * 10 is the code we wish to execute upon each element in the array. This will save each value from the numbers array, multiplied by 10, to a new array.
Like .map(), .filter() returns a new array.
However, .filter() returns an array of elements after filtering out certain elements from the original array.
The callback function for the .filter() method should return true or false depending on the element that is passed to it.
The elements that cause the callback function to return true are added to the new array.
Take a look at the following example:
const words = ['chair', 'music', 'pillow', 'brick', 'pen', 'door'];
const shortWords = words.filter(word => {
return word.length < 6;
});
words is an array that contains string elements.
const shortWords = declares a new variable that will store the returned array from invoking .filter().
The callback function is an arrow function has a single parameter, word. Each element in the words array will be passed to this function as an argument.
word.length < 6; is the condition in the callback function. Any word from the words array that has fewer than 6 characters will be added to the shortWords array.
We sometimes want to find the location of an element in an array.
That’s where the .findIndex() method comes in! Calling .findIndex() on an array will return the index of the first element that evaluates to true in the callback function.
const jumbledNums = [123, 25, 78, 5, 9];
const lessThanTen = jumbledNums.findIndex(num => {
return num < 10;
});
jumbledNums is an array that contains elements that are numbers.
const lessThanTen = declares a new variable that stores the returned index number from invoking .findIndex().
The callback function is an arrow function has a single parameter, num.
Each element in the jumbledNums array will be passed to this function as an argument.
num < 10; is the condition that elements are checked against. .findIndex() will return the index of the first element which evaluates to true for that condition.
Another widely used iteration method is .reduce().
The .reduce() method returns a single value after iterating through the elements of an array, thereby reducing the array.
Take a look at the example below:
const numbers = [1, 2, 4, 10];
const summedNums = numbers.reduce((accumulator, currentValue) => {
return accumulator + currentValue
})
console.log(summedNums) // Output: 17
Now let’s go over the use of .reduce() from the example above:
numbers is an array that contains numbers.
summedNums is a variable that stores the returned value of invoking .reduce() on numbers.
numbers.reduce() calls the .reduce() method on the numbers array and takes in a callback function as argument.
The callback function has two parameters, accumulator and currentValue.
The value of accumulator starts off as the value of the first element in the array and the currentValue starts as the second element.
To see the value of accumulator and currentValue change, review the chart above.
As .reduce() iterates through the array, the return value of the callback function becomes the accumulator value for the next iteration,
currentValue takes on the value of the current element in the looping process.
The .reduce() method can also take an optional second parameter to set an initial value for accumulator (remember, the first argument is the callback function!). For instance:
const numbers = [1, 2, 4, 10];
const summedNums = numbers.reduce((accumulator, currentValue) => {
return accumulator + currentValue
}, 100) // <- Second argument for .reduce()
console.log(summedNums); // Output: 117
There are only seven fundamental data types in JavaScript, and six of those are the primitive data types: string, number, boolean, null, undefined, and symbol.
With the seventh type, objects, we open our code to more complex possibilities.
Objects can be assigned to variables just like any JavaScript type. We use curly braces, {}, to designate an object literal:
We fill an object with unordered data. This data is organized into key-value pairs.
A key is like a variable name that points to a location in memory that holds a value.
A key’s value can be of any data type in the language including functions or other objects.
// An object literal with two key-value pairs
let spaceship = {
'Fuel Type': 'diesel',
color: 'silver'
};
The spaceship object has two properties Fuel Type and color. 'Fuel Type' has quotation marks because it contains a space character.
There are two ways we can access an object’s property.
Let’s explore the first way— dot notation,
let spaceship = {
homePlanet: 'Earth',
color: 'silver'
};
spaceship.homePlanet; // Returns 'Earth',
spaceship.color; // Returns 'silver',