Javascript

0.0(0)
studied byStudied by 0 people
0.0(0)
full-widthCall Kai
learnLearn
examPractice Test
spaced repetitionSpaced Repetition
heart puzzleMatch
flashcardsFlashcards
GameKnowt Play
Card Sorting

1/134

encourage image

There's no tags or description

Looks like no tags are added yet.

Study Analytics
Name
Mastery
Learn
Test
Matching
Spaced

No study sessions yet.

135 Terms

1
New cards

What does the console keyword refer to?

In JavaScript, the console keyword refers to an object, a collection of data and actions, that we can use in our code

2
New cards

What is a keyword?

Keywords are words that are built into the JavaScript language, so the computer recognizes them and treats them specially.

3
New cards

What does console.log() do?

When we write console.log(), what we put inside the parentheses will get printed, or logged, to the console.

It will be very useful for us to print values to the console so that we can see the work that we’re doing.

console.log(5); 

This example logs 5 to the console. The semicolon denotes the end of the line or statement.

Note: Although JavaScript code will usually run as intended without a semicolon, we recommend learning the habit of ending each statement with a semicolon so we never leave one out in the few instances where they are required.

4
New cards

What is the purpose of a comment and what are the two types of code comments in JavaScript? 

Comments can explain what the code is doing, leave instructions for developers using the code, or add any other useful annotations.

There are two types of code comments in JavaScript:

  1. A single-line comment will comment out a single line and is denoted with two forward slashes // preceding it.

// Prints 5 to the console
console.log(5);

A single-line comment may also be used after a line of code:

console.log(5);  // Prints 5 
  1. A multi-line comment will comment out multiple lines and is denoted with /* to begin the comment, and */ to end the comment.

/*
This is all commented 
console.log(10);
None of this is going to run!
console.log(99);
*/

This syntax can also be used to comment something out in the middle of a line of code:

console.log(/*IGNORED!*/ 5);  // Still just prints 5 

5
New cards

What is a data type and what are the eight fundamental data types in JavaScript? 

Data types are the classifications we give to the different kinds of data that we use in programming. In JavaScript, there are eight fundamental data types:

  • Number: Any number, including numbers with decimals: 4, 8, 1516, 23.42.

  • BigInt: Any number, greater than 253-1 or less than -(253-1), with n appended to the number: 1234567890123456n.

  • String: Any grouping of characters on the keyboard (letters, numbers, spaces, symbols, etc.) surrounded by single quotes: ' ... ' or double quotes " ... ", though we prefer single quotes. Some people like to think of string as a fancy word for text.

  • Boolean: This data type only has two possible values — either true or false (without quotes). It’s helpful to think of booleans as on and off switches or as the answers to a “yes” or “no” question.

  • Null: This data type represents the intentional absence of a value, and is represented by the keyword null (without quotes).

  • Undefined: This data type is denoted by the keyword undefined (without quotes). It also represents the absence of a value, though it has a different use than null. undefined means that a given value does not exist.

  • Symbol: A newer feature of the language, symbols are unique identifiers that are useful in more complex coding. No need to worry about these for now.

  • Object: Collections of related data.

6
New cards

What are the 7 primitive data types in JavaScript?

The seven primitive data types in JavaScript are Number, BigInt, String, Boolean, Null, Undefined, and Symbol.

7
New cards

What is operator? Additionally, what is an arithmetic operator?

An operator is a character that performs a task in our code

JavaScript has several built-in arithmetic operators, that allow us to perform mathematical calculations on numbers. These include the following operators and their corresponding symbols:

  1. Add: +

  2. Subtract: -

  3. Multiply: *

  4. Divide: /

  5. Remainder: %

The first four work as one might assume:

console.log(3 + 4); // Prints 7
console.log(5 - 1); // Prints 4
console.log(4 * 2); // Prints 8
console.log(9 / 3); // Prints 3

Note: when we console.log(), the computer will evaluate the expression inside the parentheses and print that result to the console. If we wanted to print the characters 3 + 4, we would wrap them in quotes and print them as a string.

8
New cards

What is string concatenation and what operator is used?

This process of appending one string to another is called concatenation.

When a + operator is used on two strings, it appends the right string to the left string:

console.log('hi' + 'ya'); // Prints 'hiya'
console.log('wo' + 'ah'); // Prints 'woah'
console.log('I love to ' + 'code.')
// Prints 'I love to code.'

Notice in the third example that we made sure to include a space at the end of the first string. The computer will join the strings exactly, so we must include the space we want between the two strings.

9
New cards

What is a JavaScript property? 

All data types have access to specific properties that are passed down to each instance.

For example, every string instance has a property called length that stores the number of characters in that string. We can retrieve property information by appending the string with a period and the property name:

console.log('Hello'.length); // Prints 5

The . is another operator! We call it the dot operator.

In the example above, the value saved to the length property is retrieved from the instance of the string, 'Hello'. The program prints 5 to the console because Hello has five characters in it.

10
New cards

What is a method?

Methods are actions we can perform. Data types have access to specific methods that allow us to handle instances of that data type.

We call, or use these methods by appending an instance with:

  • a period (the dot operator)

  • the name of the method

  • opening and closing parentheses

Example: 'example string'.methodName()

11
New cards

What is a variable?

In programming, a variable is a container for a value. We can think of

variablesias little containers for information that live in a computer’s memory. Information stored in variables, such as a username, account number, or personalized greeting, can then be found in memory.

Variables also provide a way of labeling data with a descriptive name, so our programs can be understood more clearly by the reader and ourselves.

In short, variables label and store data in memory. There are only a few things we can do with variables:

  1. Create a variable with a descriptive name.

  2. Store or update information stored in a variable.

  3. Reference or get information stored in a variable.

Note: It is important to distinguish that variables are not values; they contain values and represent them with a name

12
New cards

What are the general rules for naming variables? 

There are a few general rules for naming variables:

  • Variable names cannot start with numbers.

  • Variable names are case sensitive, so myName and myname would be different variables. It is bad practice to create two variables that have the same name using different cases.

  • Variable names cannot be the same as keywords. For a comprehensive list of keywords, check out MDN’s keyword documentation.

13
New cards

Prior to ES6 what was the only keyword to declare variables?

Prior to ES6, programmers could only use the var keyword to declare variables.

var, short for variable, is a JavaScript keyword that creates, or declares, a new variable.

var myName = 'Arya';
console.log(myName);
// Output: Arya

14
New cards

When was the assignment keyword let introduced? How is it different from the assignment keywords var and const?

The let keyword was introduced in ES6. The let keyword signals that the variable can be reassigned a different value later on. Take a look at the example:

let meal = 'Enchiladas';
console.log(meal); // Output: Enchiladas
meal = 'Burrito';
console.log(meal); // Output: Burrito

Another concept we should be aware of when using let (and even var) is that we can declare a variable without assigning it a value. In such a case, the variable will be automatically initialized with a value of undefined:

let price;
console.log(price); // Output: undefined
price = 350;
console.log(price); // Output: 350

Notice in the example above:

  • If we don’t assign a value to a variable declared using the let keyword, it automatically has a value of undefined.

  • We can reassign the value of the variable.

15
New cards

When was the assignment keyword const introduced? How is it different from the assignment keywords var and let?

The const keyword was also introduced in ES6, and is short for the word constant. Just like with var and let, we can store any value in a const variable. The way we declare a const variable and assign a value to it follows the same structure as let and var. Take a look at the following example:

const myName = 'Gilberto';
console.log(myName); // Output: Gilberto

However, a const variable CANNOT be reassigned because it is constant. If we try to reassign a const variable, we’ll get a TypeError.

Constant variables MUST be assigned a value when declared. If we try to declare a const variable without a value, we’ll get a SyntaxError.

16
New cards

What is string interpolation and how do we use it?

In the ES6 version of JavaScript, we can insert, or interpolate, variables into strings using template literals. Check out the following example where a template literal is used to log strings together:

const myPet = 'armadillo';
console.log(`I own a pet ${myPet}.`);
// Output: I own a pet armadillo.

Notice that:

  • A template literal is wrapped by backticks ` (this key is usually located on the top of the keyboard, left of the 1 key).

  • Inside the template literal, we’ll see a placeholder, ${myPet}. The value of myPet is inserted into the template literal.

  • When we interpolate I own a pet ${myPet}., the output we print is the string: 'I own a pet armadillo.'

One of the biggest benefits of using template literals is the readability of the code. Using template literals, we can more easily tell what the new string will be. We also don’t have to worry about escaping double quotes or single quotes.

17
New cards

Which operator can we use to check the data type of a variable’s value?

If we need to check the data type of a variable’s value, we can use the typeof operator.

The typeof operator checks the value to its right and returns, or passes back, a string of the data type.

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

Let’s break down the first example. Since the value unknown1 is 'foo', a string, typeof unknown1 will return 'string'.

18
New cards

What is an if statement and what is it composed of? 

In programming, we can perform a task based on a condition using an if statement:

if (true) {
  console.log('This message will print!'); 
}
// Prints: This message will print!

Notice in the example above, we have an if statement. The if statement is composed of:

  • The if keyword followed by a set of parentheses () which is followed by a code block, or block statement, indicated by a set of curly braces {}.

  • Inside the parentheses (), a condition is provided that evaluates to true or false.

  • If the condition evaluates to true, the code inside the curly braces {} runs, or executes.

  • If the condition evaluates to false, the block won’t execute.

19
New cards

What is an else statement and what is it composed of? 

If we wanted to add some default behavior to the if statement, we could add an else statement to run a block of code when the condition evaluates to falseTake a look at the inclusion of an else statement:

if (false) {
  console.log('The code in this block will not run.');
} 
else {
  console.log('But the code in this block will!');
}
// Prints: But the code in this block will!

An else statement must be paired with an if statement, and together they are referred to as an if...else statement.

In the example above, the else statement:

  • Uses the else keyword following the code block of an if statement.

  • Has a code block that is wrapped by a set of curly braces {}.

  • The code inside the else statement will execute when the if statement’s condition evaluates to false.

if...else statements allow us to automate solutions to yes-or-no questions, also known as binary decisions.

20
New cards

What are comparison operators?

Comparison operators compare the value on the left with the value on the right. For instance:

10 < 12 // Evaluates to true

Here is a list of some handy comparison operators and their syntax:

  • less than: <

  • greater than: >

  • less than or equal to: <=

  • greater than or equal to: >=

  • is equal to: ===

  • is not equal to: !==

It can be helpful to think of comparison statements as questions. When the answer is “yes”, the statement evaluates to true, and when the answer is “no”, the statement evaluates to false.

We can also use comparison operators on different data types like strings:

'apples' === 'oranges' // false

21
New cards

What are logical operators?

In JavaScript, there are operators that work with boolean values known as logical operators. We can use logical operators to add more sophisticated logic to our conditionals. There are three logical operators:

  • the and operator (&&)

  • the or operator (||)

  • the not operator, otherwise known as the bang operator (!)

When we use the && operator, we are checking that two things are true:

if (stopLight === 'green' && pedestrians === 0) {
  console.log('Go!');
} else {
  console.log('Stop');
}

When using the && operator, both conditions must evaluate to true for the entire condition to evaluate to true and execute. Otherwise, if either condition is false, the && condition will evaluate to false and the else block will execute.

If we only care about either condition being true, we can use the || operator:

if (day === 'Saturday' || day === 'Sunday') {
  console.log('Enjoy the weekend!');
} else {
  console.log('Do some work.');
}

When using the || operator, only one of the conditions must evaluate to true for the overall statement to evaluate to true. In the code example above, if either day === 'Saturday' or day === 'Sunday' evaluates to true, the if condition will evaluate to true and its code block will execute. If the first condition in an || statement evaluates to true, the second condition won’t even be checked. Only if day === 'Saturday' evaluates to false will day === 'Sunday' be evaluated. The code in the else statement above will execute only if both comparisons evaluate to false.

The ! not operator reverses, or negates, the value of a boolean:

let excited = true;
console.log(!excited); // Prints false

let sleepy = false;
console.log(!sleepy); // Prints true

Essentially, the ! operator will either take a true value and pass back false, or it will take a false value and pass back true.

Logical operators are often used in conditional statements to add another layer of logic to our code.

22
New cards

What are Truthy and Falsy values? 

Sometimes, you’ll want to check if a variable exists and you won’t necessarily want it to equal a specific value — you’ll only check to see if the variable has been assigned a value.

Here’s an example:

let myVariable = 'I Exist!';

if (myVariable) {
   console.log(myVariable)
} else {
   console.log('The variable does not exist.')
}

The code block in the if statement will run because myVariable has a truthy value; even though the value of myVariable is not explicitly the value true, when used in a boolean or conditional context, it evaluates to true because it has been assigned a non-falsy value.

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 represents when there is no value at all

  • undefined, which represents when a declared variable lacks a value

  • NaN, or Not a Number

Here’s an example with numbers:

let numberOfApples = 0;

if (numberOfApples){
   console.log('Let us eat apples!');
} else {
   console.log('No apples left!');
}

// Prints 'No apples left!'

The condition evaluates to false because the value of numberOfApples is 0. Since 0 is a falsy value, the code block in the else statement will run.

23
New cards
24
New cards

What is a ternary operator?

In the spirit of using short-hand syntax, we can use a ternary operator to simplify an if...else statement.

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!');

In the example above:

  • The condition, isNightTime, is provided before the ?.

  • Two expressions follow the ? and are separated by a colon :.

  • If the condition evaluates to true, the first expression executes.

  • If the condition evaluates to false, the second expression executes.

Like if...else statements, ternary operators can be used for conditions that evaluate totrueorfalse.

25
New cards

What is an else if statement?

We can add more conditions to our if...else with an else if statement. The else if statement allows for more than two possible outcomes. You can add as many else if statements as you’d like, to make more complex conditionals!

The else if statement always comes after the if statement and before the else statement. The else if statement also takes a condition. Let’s take a look at the syntax:

let stopLight = 'yellow';

if (stopLight === 'red') {
  console.log('Stop!');
} else if (stopLight === 'yellow') {
  console.log('Slow down.');
} else if (stopLight === 'green') {
  console.log('Go!');
} else {
  console.log('Caution, unknown!');
}

The else if statements allow you to have multiple possible outcomes. if/else if/else statements are read from top to bottom, so the first condition that evaluates to true from the top to bottom is the block that gets executed.

In the example above, since stopLight === 'red' evaluates to false and stopLight === 'yellow' evaluates to true, the code inside the first else if statement is executed. The rest of the conditions are not evaluated. If none of the conditions evaluated to true, then the code in the else statement would have executed.

26
New cards

What is a switch statement? Why might we prefer using it over else ifs?

A switch statement provides an alternative syntax that is easier to read and write. Aswitchstatement looks like this:

let groceryItem = 'papaya';

switch (groceryItem) {
  case 'tomato':
    console.log('Tomatoes are $0.49');
    break;
  case 'lime':
    console.log('Limes are $1.49');
    break;
  case 'papaya':
    console.log('Papayas are $1.29');
    break;
  default:
    console.log('Invalid item');
    break;
}

// Prints 'Papayas are $1.29'
  • The switch keyword initiates the statement and is followed by ( ... ), which contains the value that each case will compare. In the example, the value or expression of the switch statement is groceryItem.

  • Inside the block, { ... }, there are multiple cases. The case keyword checks if the expression matches the specified value that comes after it. The value following the first case is 'tomato'. If the value of groceryItem equalled 'tomato', the console.log() of that case would run.

  • The value of groceryItem is 'papaya', so the third case runs — 'Papayas are $1.29' is logged to the console.

  • The break keyword tells the computer to exit the block and not execute any more code or check any other cases inside the code block. Note: Without break keywords, the first matching case will run, but so will every subsequent case, regardless of whether or not it matches—including the default. This behavior is different from if/else conditional statements that execute only one block of code.

  • At the end of each switch statement, there is a default statement. If none of the case statements are true, then the code in the default statement will run.

27
New cards

What does a function declaration consist of?

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, { }

A function declaration is a function that is bound to an identifier, or name. In the next exercise, we’ll go over how to run the code inside the function body.

We should also be aware of the hoisting feature in JavaScript, which allows access to function declarations before they’re defined.

Take a look at an example of hoisting:

greetWorld(); // Output: Hello, World!

function greetWorld() {
  console.log('Hello, World!');
}

Notice how hoisting allowed greetWorld() to be called before the greetWorld() function was defined! Since hoisting isn’t considered good practice, we simply want to point out this feature.

28
New cards

How do we call a function?

To call a function, type the function name followed by parentheses.

This function call executes the function body, or all of the statements between the curly braces in the function declaration.

We can call the same function as many times as needed.

29
New cards

What are parameters and arguments?

When declaring a function, we can specify its parameters. Parameters allow functions to accept input(s) and perform a task using the input(s). We use parameters as placeholders for information that will be passed to the function when it is called.

Let’s observe how to specify parameters in our function declaration:


In the diagram above, calculateArea() computes the area of a rectangle, based on two inputs, width and height. The parameters are specified between the parentheses as width and height, and inside the function body, they act just like regular variables. The parameters width and height act as placeholders for values that will be multiplied together.

When calling a function that has parameters, we specify the values in the parentheses that follow the function name. The values that are passed to the function when it is called are called arguments. Arguments can be passed to the function as values or variables.

In the function call above, the number 10 is passed as the width and 6 is passed as the height. Notice that the order in which arguments are passed and assigned follows the order in which the parameters are declared.

The variables rectWidth and rectHeight are initialized with the values for the height and width of a rectangle before being used in the function call.

By using parameters, calculateArea() can be reused to compute the area of any rectangle! Functions are a powerful tool in computer programming, so let’s practice creating and calling functions with parameters.

30
New cards

What are default parameters and what do they allows us to do?

Default parameters allow parameters to have a predetermined value in case no argument is passed into the function or if the argument is undefined when called.

Take a look at the code snippet below that uses a default parameter:

function greeting (name = 'stranger') {
  console.log(`Hello, ${name}!`)
}

greeting('Nick') // Output: Hello, Nick!
greeting() // Output: Hello, stranger!
  • In the example above, we used the = operator to assign the parameter name a default value of 'stranger'. This is useful to have in case we ever want to include a non-personalized default greeting!

  • When the code calls greeting('Nick'), the value of the argument is passed in and 'Nick', will override the default parameter of 'stranger' to log 'Hello, Nick!' to the console.

  • When there isn’t an argument passed into greeting(), the default value of 'stranger' is used, and 'Hello, stranger!' is logged to the console.

By using a default parameter, we account for situations when an argument isn’t passed into a function that is expecting an argument.

31
New cards

How do we pass back information from a function call?

To pass back information from a function call, we use a return statement. To create a return statement, we use the return keyword followed by the value that we wish to return. If the value is omitted, undefined is returned instead.

When a return statement is used in a function body, the execution of the function is stopped, and the code that follows it will not be executed. Look at the example below:

function rectangleArea(width, height) {
  if (width < 0 || height < 0) {
    return 'You need positive integers to calculate area!';
  }
  return width * height;
}

If an argument for width or height is less than 0, then rectangleArea() will return 'You need positive integers to calculate area!'. The second return statement — width * height — will not run.

The return keyword is powerful because it allows functions to produce an output. We can then save the output to a variable for later use.

32
New cards

What are helper functions?

We can also use the return value of a function inside another function. These functions being called within another function are often referred to as helper functions. Since each function is carrying out a specific task, it makes our code easier to read and debug if necessary.

If we wanted to define a function that converts the temperature from Celsius to Fahrenheit, we could write two functions like:

function multiplyByNineFifths(number) {
  return number * (9/5);
};

function getFahrenheit(celsius) {
  return multiplyByNineFifths(celsius) + 32;
};

getFahrenheit(15); // Returns 59

In the example above:

  • getFahrenheit() is called with 15 passed as an argument.

  • The code block inside of getFahrenheit() calls multiplyByNineFifths() and passes 15 as an argument.

  • multiplyByNineFifths() takes the argument of 15 for the number parameter.

  • The code block inside of multiplyByNineFifths() function multiplies 15 by (9/5), which evaluates to 27.

  • 27 is returned to the function call in getFahrenheit().

  • getFahrenheit() continues to execute. It adds 32 to 27, which evaluates to 59.

  • Finally, 59 is returned to the function call getFahrenheit(15).

We can use functions to section off small bits of logic or tasks and then use them when necessary. Writing helper functions can help break large and difficult tasks into smaller and more manageable tasks.

33
New cards

What is a function expression? How do you define it?

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.

Consider the following function expression:

To declare a function expression:

  1. Declare a variable to make the variable’s name the name, or identifier, of the function. Since the release of ES6, it is common practice to use const as the keyword to declare a variable.

  2. 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 contains the function body.

To invoke a function expression, write the name of the variable in which the function is stored, followed by parentheses enclosing any arguments being passed into the function.

variableName(argument1, argument2)

NOTE: Unlike function declarations, function expressions are not hoisted, so they cannot be called before they are defined.

34
New cards

What are arrows functions and how do you declare them?

ES6 introduced arrow function syntax, a shorter way to write

functions

Preview: Docs Loading link description

by using the special “fat arrow”() =>notation.

Arrow functions remove the need to type out the keyword function every time we create a function. Instead, we 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;
};

35
New cards

What is a concise body?

JavaScript also provides several ways to refactor arrow function syntax. The most condensed form of the function is known as aconcise body. We’ll explore a few of these techniques below:

  1. 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.

  1. 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.

So if we have a function:

const squareNum = (num) => {
  return num * num;
};

We can refactor the function to:

const squareNum = num => num * num;

Notice the following changes:

  • The parentheses around num have been removed, since it has a single parameter.

  • The curly braces { } have been removed since the function consists of a single-line block.

  • The return keyword has been removed since the function consists of a single-line block.

36
New cards

What is a block?

We’ve seen blocks used before in functions andif statements. A block is the code found inside a set of curly braces{}. Blocks help us group one or more statements together and serve as an important structural marker for our code.

A function contains a block of code as its body, like this:

const logSkyColor = () => {
  let color = 'blue'; 
  console.log(color); // blue 
}

Notice that the function body is actually a block of code.

Observe the block in an if statement:

if (dusk) {
  let color = 'pink';
  console.log(color); // pink
}

37
New cards

What is scope?

Scope is the context in which our variables are declared. We think about scope in relation to blocks because variables can exist either outside of or within these blocks.

38
New cards

What is global scope?

In the global scope, variables are declared outside of blocks. These variables are called global variables. Because global variables are not bound inside a block, they can be accessed by any code in the program, including code in blocks.

Let’s take a look at an example of global scope:

const color = 'blue';

const returnSkyColor = () => {
  return color; // blue 
};

console.log(returnSkyColor()); // blue

Even though the color variable is defined outside of the function, it can still be accessed inside the returnSkyColor() function.

39
New cards

What is a block scope?

When a variable is defined inside a block, it is only accessible to the code within the curly braces {}. We say that a variable has block scope because it is only accessible to the lines of code within that block.

Variables declared with block scope are known as local variables because they are only available to the code that is part of the same block.

Block scope works like this:

const logSkyColor = () => {
  let color = 'blue'; 
  console.log(color); // Prints "blue"
};

logSkyColor(); // Prints "blue"
console.log(color); // throws a ReferenceError

Notice the following:

  • We define a function logSkyColor().

  • Within the function, the color variable is only available within the curly braces of the function.

  • If we try to log the same variable outside the function, it throws a ReferenceError.

40
New cards

What is the global namespace?

It may seem like a great idea to always make variables globally accessible, but having too many global variables can cause problems in a program.

When declaring global variables, they go to the global namespace. The global namespace allows the variables to be accessible from anywhere in the program. These variables remain there until the program finishes, which means our global namespace can fill up really quickly.

41
New cards

What is scope pollution?

Scope pollution occurs when we have too many variables in the global namespace, or when we reuse variables across different scopes. Scope pollution makes it difficult to keep track of our different variables and sets us up for potential accidents. For example, globally scoped variables can collide with other variables that are more locally scoped, causing unexpected behavior in our code.

Let’s look at an example of scope pollution in practice so we know how to avoid it:

let num = 50;

const logNum = () => {
  num = 100; // Take note of this line of code
  console.log(num);
};

logNum(); // Prints 100
console.log(num); // Prints 100

Notice that:

  • We have a variable num.

  • Inside the function body of logNum(), we want to declare a new variable, but forgot to use the let keyword.

  • When we call logNum(), num gets reassigned to 100.

  • The reassignment inside logNum() affects the global variable num.

  • Even though the reassignment is allowed and we won’t get an error, if we decide to use num later, we’ll unknowingly use the new value of num.

While it’s important to know what global scope is, it’s best practice to not define variables in the global scope when possible.

42
New cards

What are good scoping practices?

Given the challenges with global

variables and scope pollution, we should follow best practices for scoping our variables as tightly as possible using block scope.

Tightly scoping variables will greatly improve code in several ways:

  • It will make the code more legible since the blocks will organize the code into discrete sections.

  • It makes the code more understandable by clarifying which variables are associated with different parts of the program, rather than having to keep track of them line by line!

  • It’s easier to maintain tightly scoped code, as it will be modular.

  • It will save memory because variables with block scope will cease to exist after the block finishes running.

Here’s another example of how block scope works, as defined within an if block:

const logSkyColor = () => {
  const dusk = true;
  let color = 'blue'; 
  if (dusk) {
    let color = 'pink';
    console.log(color); // Prints "pink"
  }
  console.log(color); // Prints "blue"
};

console.log(color); // throws a ReferenceError

Here, notice that:

  • We create a variable color inside the logSkyColor() function.

  • After the if statement, we create a new block with { } braces, where we declare a new color variable using let and assign it a value if the if condition is truthy.

  • Within the if block, the color variable holds the value 'pink', though outside the if block, in the function body, the color variable holds the value 'blue'.

  • On the last line, we attempt to print the value of color outside both the if statement and the definition of logSkyColor(). This will throw a ReferenceError since color only exists within the scope of those two blocks — it is never defined in the global scope.

  • While we use block scope, we still pollute our namespace by reusing the same variable name twice. A better practice would be to rename the variable inside the block.

Block scope is a powerful tool in JavaScript, since it allows us to define variables with precision and not pollute the global namespace. If a variable does not need to exist outside a block, it shouldn’t!

43
New cards

What is an array literal?

One way we can create an array is to use an array literal. An array literal creates an array by wrapping items in square brackets []. Arrays can store any data type — we can have an array that holds all the same data types or an array that holds different data types.

Let’s take a closer look at the syntax in the array example:

  • The array is represented by the square brackets [] and the content inside.

  • Each content item inside an array is called an element.

  • Each element is separated by a comma.

  • There are three different elements inside the array.

  • Each element inside the array is a different data type.

We can also save an array to a variable.

let newYearsResolutions = ['Keep a journal', 'Take a falconry class', 'Learn to juggle'];

44
New cards

How can we access an array element? 

Each element in an array has a numbered position known as its index. We can access individual items using their index, which is similar to referencing an item in a list based on the item’s 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. Let’s see how we could access an element in an array:

In the code snippet above:

  • cities is an array that has three elements: 'New York', 'Beijing', and 'Nairobi'.

  • We’re using bracket notation, [], with the index after the name of the array to access the element.

  • cities[0] will access the element at index 0 in the array cities. We can think of cities[0] as accessing the space in memory that holds the string 'New York'.

We can also access individual characters in a string using bracket notation and the index. For instance, we can write:

const hello = 'Hello World';
console.log(hello[6]);
// Output: W

The console will display W since it is the character that is at index 6.

Note: Attempting to access an index that is out of range will result in a value of undefined.

45
New cards

How can we update an array element?

With access to an element in an array, we can also update its value.

let seasons = ['Winter', 'Spring', 'Summer', 'Fall'];

seasons[3] = 'Autumn';
console.log(seasons); 
//Output: ['Winter', 'Spring', 'Summer', 'Autumn']

In the example above, the seasons array contained the names of the four seasons.

However, we decided that we preferred to say 'Autumn' instead of 'Fall'.

This line — seasons[3] = 'Autumn'; — updates the item at index 3 of the seasons array, replacing 'Fall' with 'Autumn'.

46
New cards

What is the different between an array declared with let vs an array declared with const?

Recall that we can declare variables with both theletandconstkeywords.

Variables declared with let can be reassigned, i.e.:

let condiments = ['Ketchup', 'Mustard', 'Soy Sauce', 'Sriracha'];

condiments = ['Mayo'];
console.log(condiments); // Results in [ 'Mayo' ]

Variables declared with the const keyword cannot be reassigned, i.e.:

const utensils = ['Fork', 'Knife', 'Chopsticks', 'Spork'];

utensils = ['Spoon']; // This will result in an error!

However, elements in an array declared with const remain mutable. This means that we can change the contents of a const array, but cannot reassign a new array or a different value.

let condiments = ['Ketchup', 'Mustard', 'Soy Sauce', 'Sriracha'];

condiments[0] = 'Mayo';
console.log(condiments); // Will result in [ 'Mayo', 'Mustard', 'Soy Sauce', 'Sriracha' ]



const utensils = ['Fork', 'Knife', 'Chopsticks', 'Spork'];

utensils[3] = 'Spoon';
console.log(utensils); // Will result in [ 'Fork', 'Knife', 'Chopsticks', 'Spoon' ]

47
New cards

Which built-in property of an array can we use to determine the number of items in the array? 

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

In the example above, we log newYearsResolutions.length to the console using the following steps:

  • We use dot notation, chaining a period with the property name to the array, to access the length property of the newYearsResolutions array.

  • Then, we log the length of newYearsResolutions to the console.

  • Since newYearsResolutions has two elements, 2 would be logged to the console.

When we want to know the number of elements in an array, we can access the .length property.

48
New cards

Which method allows us to add items to the end of an array?

The .push() method 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'];

So, how does .push() work?

  • We access the push() method by using dot notation, connecting push() to itemTracker with a period.

  • Then, we call it like a function. That’s because .push() is a function that JavaScript allows us to use directly on an array.

  • .push() can take a single argument or multiple arguments separated by commas. In this case, we’re adding two elements: 'item 3' and 'item 4' to itemTracker.

  • Notice that .push() changes, or mutates, itemTracker. .push() is sometimes also referred to as a destructive array method since it changes the initial array.

When looking for a method that will mutate an array by adding one or more elements to it, .push() is the correct choice!

49
New cards

Which method allows us to remove the last item of an array?

The .pop() method removes the last element 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
  • In the example above, calling .pop() on the newItemTracker array removed 'item 2' from the end.

  • .pop() does not take any arguments — it simply removes the last element of newItemTracker.

  • .pop() returns the value of the last element. In the example, we store the returned value in a variable removed to be used later.

  • .pop() is a method that mutates the initial array.

When an array needs to be mutated by removing the last element, use .pop().

50
New cards

Which method allows us to remove the first element of an array?

The .shift() method to remove the first item from the array

const groceryList = ['orange juice', 'bananas', 'coffee beans', 'brown rice', 'pasta', 'coconut oil', 'plantains'];

groceryList.shift();
console.log(groceryList);
/* 
  [
    'bananas',
    'coffee beans',
    'brown rice',
    'pasta',
    'coconut oil',
    'plantains'
  ]		
*/

51
New cards

Which method adds an element to the beginning of the array?

The .unshift() method to adds an element to the beginning of the array.

const groceryList = ['orange juice', 'bananas', 'coffee beans', 'brown rice', 'pasta', 'coconut oil', 'plantains'];

groceryList.unshift('popcorn');
console.log(groceryList);
/*
  [
    'popcorn',
    'orange juice',
    'bananas',
    'coffee beans',
    'brown rice',
    'pasta',
    'coconut oil',
    'plantains'
  ]
*/

52
New cards

Which method returns a partial copy of an array, otherwise known as a shallow copy, without altering the original array.

The .slice() method in JavaScript returns a partial copy of an array, otherwise known as a shallow copy, without altering the original array.

Syntax:

array.slice(start, end);
  • array: The name of the array to be sliced.

  • start (optional): The index at which the method will begin copying. If omitted, the process of copying elements starts with the array’s first element.

  • end (optional): The index before which the method will stop copying. The element located at this index is not copied to the new array.

53
New cards

Which method finds the index of a particular element?

The .indexOf() method finds the index of a particular element of an array.

const groceryList = ['orange juice', 'bananas', 'coffee beans', 'brown rice', 'pasta', 'coconut oil', 'plantains'];

const pastaIndex = groceryList.indexOf('pasta');
console.log(pastaIndex);

/*
   4
*/

54
New cards

If an array is mutated inside of a function will that change be maintained outside of the function as well?

Take a look at the following example where we call .push()on an array inside a function. Recall, the.push()method mutates, or changes, an array:

const flowers = ['peony', 'daffodil', 'marigold'];

function addFlower(arr) {
  arr.push('lily');
}

addFlower(flowers);

console.log(flowers); // Output: ['peony', 'daffodil', 'marigold', 'lily']

Let’s go over what happened in this example:

  • The flowers array starts with three elements.

  • The function addFlower() has a parameter of arr and uses .push() to add a 'lily' element into arr.

  • We call addFlower() with an argument of flowers, which will execute the code inside addFlower.

  • We check the value of flowers and it now includes the 'lily' element! The array was mutated!

So when we pass an array into a function, if the array is mutated inside the function, that change will be maintained outside the function as well. This concept is also sometimes called pass-by-reference, since what we’re actually passing to the function is a reference to where the variable is stored in memory and changing the data there.

55
New cards

What is a nested array?

When an array contains another array, it is known as a nested array. Examine the following example:

const nestedArr = [[1], [2, 3]];

To access the nested arrays, we can use bracket notation with the index value, just like we did to access any other element:

const nestedArr = [[1], [2, 3]];

console.log(nestedArr[1]); // Output: [2, 3]

Notice that nestedArr[1] will grab the element in index 1, which is the array [2, 3]. Then, we can access the elements within the nested array by chaining, or adding on, more bracket notation with index values.

const nestedArr = [[1], [2, 3]];

console.log(nestedArr[1]); // Output: [2, 3]
console.log(nestedArr[1][0]); // Output: 2

In the second console.log() statement, we have two bracket notations chained to nestedArr. We know that nestedArr[1] is the array [2, 3]. Then, to grab the first element from that array, we use nestedArr[1][0] and we get the value of 2.

56
New cards

What is a loop?

A loop is a programming tool that repeats a set of instructions until a specified condition, called a stopping condition is reached. 

57
New cards

What is a for loop? What is it used for?

Instead of writing out the same code over and over, loops allow us to tell the computer to repeat a given block of code on its own. One way to give computers these instructions is with a for loop.

The typical for loop includes an iterator variable that usually appears in all three expressions. The iterator variable is initialized, checked against the stopping condition, and assigned a new value on each loop iteration. Iterator

variables can have any name, but it’s best practice to use a descriptive variable name.

A for loop contains three expressions separated by ; inside the parentheses:

  1. an initialization starts the loop and can also be used to declare the iterator variable.

  2. a stopping condition is the condition that the iterator variable is evaluated against — if the condition evaluates to true, the code block will run. If it evaluates to false, the code will stop.

  3. an iteration statement is used to update the iterator variable on each loop.

The for loop syntax looks like this:

for (let counter = 0; counter < 4; counter++) {
  console.log(counter);
}

In this example, the output would be the following:

0
1
2
3

Let’s break down the example:

  • The initialization is let counter = 0, so the loop will start counting at 0.

  • The stopping condition is counter < 4, meaning the loop will run as long as the iterator variable, counter, is less than 4.

  • The iteration statement is counter++. This means after each loop, the value of counter will increase by 1. For the first iteration, counter will equal 0. For the second iteration, it will equal 1, and so on.

  • The code block within the curly braces, console.log(counter), will continue to execute until the condition evaluates to false. The condition will be false when counter is greater than or equal to 4 — the point that the condition becomes false is sometimes called the stop condition.

This for loop makes it possible to write 0, 1, 2, and 3 programmatically.

58
New cards

How can we run a for loop in reverse?

To run a

backward for loop, we must:

  • Set the iterator variable to the highest desired value in the initialization expression.

  • Set the stopping condition for when the iterator variable is less than the lowest desired amount.

  • The iterator should decrease in intervals after each iteration.

for(let i = 3 ; i > 0; i--){
  console.log(i);
}
3
2
1

When writing/changing loops, there is a chance we will get a dreaded infinite loop, which essentially stops our programming from running anything else! This occurs when the loop’s stopping condition is never met, causing the loop to continue iterating, blocking the rest of the program from executing.

59
New cards

How do we loop through an array?

To loop through each element in an array, a for loop should use the array’s .length property in its condition.

Check out the example below to see how for loops iterate on arrays:

const animals = ['Grizzly Bear', 'Sloth', 'Sea Lion'];
for (let i = 0; i < animals.length; i++){
  console.log(animals[i]);
}

This example would give you the following output:

Grizzly Bear
Sloth
Sea Lion

In the loop above, we’ve named our iterator variable i. This is a variable naming convention you’ll see in a lot of loops. When we use i to iterate through arrays we can think of it as being short-hand for the word index. Notice how our stopping condition checks that i is less than animals.length. Remember that arrays are zero-indexed, the index of the last element of an array is equivalent to the length of that array minus 1. If we tried to access an element at the index of animals.length we will have gone too far!

With for loops, it’s easier for us to work with elements in arrays.

60
New cards

What are nested loops? 

When one loop is running inside another loop, we call that a nested loop. One use for a nested for loop is to compare the elements in two

arrays. For each round of the outer for loop, the inner for loop will run completely.

Let’s look at an example of a nested for loop:

const arrayA = [6, 19, 20];
const arrayB = [19, 81, 2];
for (let i = 0; i < arrayA.length; i++) {
  for (let j = 0; j < arrayB.length; j++) {
    if (arrayA[i] === arrayB[j]) {
      console.log('Both arrays have the number: ' + arrayB[j]);
    }
  }
}

Let’s think about what’s happening in the nested loop in our example. For each element in the outer loop array, arrayA, the inner loop will run in its entirety comparing the current element from the outer array, arrayA[i], to each element in the inner array, arrayB[j]. When it finds a match, it prints a string to the console.

61
New cards

What is the while loop?

Now, we’re going to learn about a different type of loop: the

while loop. To start, let’s convert aforloop into awhileloop:

// A for loop that prints 1, 2, and 3
for (let counterOne = 1; counterOne < 4; counterOne++){
  console.log(counterOne);
}

// A while loop that prints 1, 2, and 3
let counterTwo = 1;
while (counterTwo < 4) {
  console.log(counterTwo);
  counterTwo++;
}

Let’s break down what’s happening with our while loop syntax: The counterTwo variable is declared before the loop. Since it’s in the global scope, we can access it inside our while loop.

  • We start our loop with the keyword while followed by our stopping condition, or test condition. This will be evaluated before each round of the loop. While the condition evaluates to true, the block will continue to run. Once it evaluates to false the loop will stop.

  • Next, we have our loop’s code block, which prints counterTwo to the console and increments counterTwo.

What would happen if we didn’t increment counterTwo inside our block? If we didn’t include this, counterTwo would always have its initial value, 1. That would mean the testing condition counterTwo < 4 would always evaluate to true and our loop would never stop running! Remember, this is called an infinite loop and it’s something we always want to avoid. Infinite loops can take up all of a computer’s processing power, potentially freezing the machine.

So you may be wondering when to use a while loop! The syntax of a while loop is ideal when we don’t know in advance how many times the loop should run. Think of eating like a while loop: when you start taking bites, you don’t know the exact number you’ll need to become full. Rather, you’ll eat while you’re hungry. In situations when we want a loop to execute an undetermined number of times, while loops are the best choice.

62
New cards

What is the do while loop? How is it different from a regular while loop?

In some cases, we want a piece of code to run at least once and then loop based on a specific condition after its initial run. This is where the do...while statement comes in.

A do...while statement says to do a task once and then keep doing it until a specified condition is no longer met. The syntax for ado...whilestatement looks like this:

let countString = '';
let i = 0;

do {
  countString = countString + i;
  i++;
} while (i < 5);

console.log(countString);

In this example, the code block makes changes to the countString variable by appending the string form of the i variable to it. First, the code block after the do keyword is executed once. Then the condition is evaluated. If the condition evaluates to true, the block will execute again. The looping stops when the condition evaluates to false.

Note that the while and do...while loops are different! Unlike the while loop, do...while will run at least once, whether or not the condition evaluates to true.

const firstMessage = 'I will print!';
const secondMessage = 'I will not print!'; 

// A do while with a stopping condition that evaluates to false
do {
 console.log(firstMessage)
} while (true === false);

// A while loop with a stopping condition that evaluates to false
while (true === false){
  console.log(secondMessage)
};

63
New cards

What does the break keyword do?

The break keyword allows programs to “break” out of the loop from within the loop’s block.

Let’s check out the syntax of a break keyword:

for (let i = 0; i < 99; i++) {
  if (i > 2 ) {
     break;
  }
  console.log('Banana.');
}

console.log('Orange you glad I broke out the loop!');

This is the output for the above code:

Banana.
Banana.
Banana.
Orange you glad I broke out the loop!

break  statements can be especially helpful when we’re looping through large data structures! With breaks, we can add test conditions besides the stopping condition, and exit the loop when they’re met.

64
New cards

Can we assign functions to variables and reassign them to new variables?

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.

Below, we have an annoyingly long function name that hurts the readability of any code in which it’s used.

const announceThatIAmDoingImportantWork = () => {
    console.log("I’m doing very important work!");
};

Let’s pretend this function does important work and needs to be called repeatedly. To rename this function without sacrificing the source code, we can re-assign the function to a variable with a suitably short name:

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 were the name we originally gave our function.

NOTE: Notice how we assign announceThatIAmDoingImportantWork without parentheses as the value to the busy variable. We want to assign the value of the function itself, not the value it returns when invoked.

65
New cards

Are functions first-class objects?

In JavaScript, functions are first-class objects. This means that, like other objects we’ve encountered, JavaScript functions can have properties and methods.

Since functions are a type of object, they have properties such as .length and .name, and methods such as .toString().

Functions are special because we can invoke them, but we can still treat them like any other type of data

66
New cards

Can functions serve as parameters as well?

Since functions can behave like any other type of data in JavaScript, it may not be a surprise to learn that functions can accept other functions as parameters.A higher-order function is a function that either accepts functions as parameters, returns a function, or both! We call functions that get passed in as parameters callback functions. Callback functions get invoked during the execution of the higher-order function.

When we invoke a higher-order function and pass another function in as an argument, we don’t invoke the argument function. Invoking it would evaluate to passing in the return value of that function call. With callback functions, we pass in the function itself by typing the function name without the parentheses:

const higherOrderFunc = param => {
  param();
  return `I just invoked ${param.name} as a callback function!`
}
 
const anotherFunc = () => {
  return 'I\'m being invoked by the higher-order function!';
}

higherOrderFunc(anotherFunc);

We wrote a higher-order function higherOrderFunc that accepts a single parameter, param. Inside the body, param gets invoked using parentheses. And finally, a string is returned, telling us the name of the callback function that was passed in.

Below the higher-order function, we have another function aptly named anotherFunc. Then, we invoke higherOrderFunc(), passing in anotherFunc as its argument.

higherOrderFunc(() => {
  for (let i = 0; i <= 10; i++){
    console.log(i);
  }
});

In this example, we invoked higherOrderFunc() with an anonymous function (a function without a name) that counts to 10. Anonymous functions can be arguments too!

67
New cards

What are iterators?

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.

68
New cards

What does the .forEach() iteration method do?

Aptly named, .forEach() will execute the same code for each element of an array.

The preceding code example 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 a callback function as an argument. Remember, a callback function is a function passed as an argument to another function.

  • .forEach()

    loops

    Preview: Docs Loading link description

    through the array and executes the callback function for each element. During each execution, the current element is passed as the argument for 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);

The preceding example uses a function declaration, but we can also use a function expression or arrow function.

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.

69
New cards

What does the .map() iterator function do?

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.

If we take a look at numbers and bigNumbers:

console.log(numbers); // Output: [1, 2, 3, 4, 5]
console.log(bigNumbers); // Output: [10, 20, 30, 40, 50]

Notice that the elements in numbers were not altered and bigNumbers is a new array.

70
New cards

What does the .filter() iterator method do?

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 returntrueorfalsedepending on the element that is passed to it. The elements that cause the callback function to returntrueare 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 that takes 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.

Let’s also check the values of words and shortWords:

console.log(words); // Output: ['chair', 'music', 'pillow', 'brick', 'pen', 'door']; 
console.log(shortWords); // Output: ['chair', 'music', 'brick', 'pen', 'door']

Observe how words was not mutated, i.e. changed, and shortWords is a new array.

71
New cards

What does the .findIndex() iterator method do?

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 that 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 that evaluates to true for that condition.

Let’s take a look at what lessThanTen evaluates to:

console.log(lessThanTen); // Output: 3 

If we check what element has index of 3:

console.log(jumbledNums[3]); // Output: 5

Great, the element in index 3 is the number 5. This makes sense since 5 is the first element that is less than 10.

If there isn’t a single element in the array that satisfies the condition in the callback, then .findIndex() will return -1.

const greaterThan1000 = jumbledNums.findIndex(num => {
  return num > 1000;
});

console.log(greaterThan1000); // Output: -1

72
New cards

What does the .reduce() iterator method do?

The .reduce() method returns a single value after iterating through the elements of an array, thereby reducing the array. Take a look at the following example:

const numbers = [1, 2, 4, 10];

const summedNums = numbers.reduce( (accumulator, currentValue) => {
  return accumulator + currentValue
})

console.log(summedNums) // Output: 17

Here are the values of accumulator and currentValue as we iterate through the numbers array:

Iteration

accumulator

currentValue

return value

First

1

2

3

Second

3

4

7

Third

7

10

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 an 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 values 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

Here’s an updated chart that accounts for the second argument of 100:

Iteration #

accumulator

currentValue

return value

First

100

1

101

Second

101

2

103

Third

103

4

107

Fourth

107

10

117


73
New cards

What does the .every() iterator method do?

74
New cards

How can we create object literals?

Objects can be assigned to variables just like any JavaScript type. We use curly braces,{}, to designate an object literal:

let spaceship = {}; // spaceship is an empty object

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.

We make a key-value pair by writing the key’s name, or identifier, followed by a colon and then the value. We separate each key-value pair in an object literal with a comma (,). Keys are strings, but when we have a key that does not have any special characters in it, JavaScript allows us to omit the quotation marks:

// 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.

75
New cards

What are the two ways we can access an object’s property?

There are two ways we can access an object’s property. Let’s explore the first way — dot notation (.).

We’ve used dot notation to access the properties and methods of built-in objects and data instances:

'hello'.length; // Returns 5

With property dot notation, we write the object’s name, followed by the dot operator, and then the property name (key):

let spaceship = {
  homePlanet: 'Earth',
  color: 'silver'
};
spaceship.homePlanet; // Returns 'Earth'
spaceship.color; // Returns 'silver'

If we try to access a property that does not exist on that object, undefined will be returned.

spaceship.favoriteIcecream; // Returns undefined

The second way to access a key’s value is by using bracket notation, [ ].

To use bracket notation to access an object’s property, we pass in the property name (key) inside square brackets as a string.

We must use bracket notation when accessing keys that are not valid identifier names (e.g., keys that begin with a number or contain spaces or special characters). Without bracket notation in these situations, our code would throw an error.

let spaceship = {
  'Fuel Type': 'Turbo Fuel',
  'Active Duty': true,
  homePlanet: 'Earth',
  numCrew: 5
};
spaceship['Active Duty'];   // Returns true
spaceship['Fuel Type'];   // Returns 'Turbo Fuel'
spaceship['numCrew'];   // Returns 5
spaceship['!!!!!!!!!!!!!!!'];   // Returns undefined

With bracket notation, you can also use a variable inside the brackets to select the keys of an object. This can be especially helpful when working with functions:

let returnAnyProp = (objectName, propName) => objectName[propName];
 
returnAnyProp(spaceship, 'homePlanet'); // Returns 'Earth'

If we tried to write our returnAnyProp() function with dot notation (objectName.propName), the computer would look for a key of 'propName' on our object and not the value of the propName parameter.

76
New cards

How do we update object values?

Once we’ve defined an object, we’re not stuck with all the properties we wrote.

Objects are mutable, meaning we can update them after we create them!

We can use either dot notation (.) or bracket notation ([]), along with the assignment operator (=), to add new key-value pairs to an object or change an existing property.

One of two things can happen with property assignment:

  • If the property already exists on the object, whatever value it held before will be replaced with the newly assigned value.

  • If there was no property with that name, a new property will be added to the object.

It’s important to know that although we can’t reassign an object declared with const, we can still mutate it, meaning we can add new properties and change the properties that are there.

const spaceship = {type: 'shuttle'};
spaceship = {type: 'alien'}; // TypeError: Assignment to constant variable.
spaceship.type = 'alien'; // Changes the value of the type property
spaceship.speed = 'Mach 5'; // Creates a new key of 'speed' with a value of 'Mach 5'

77
New cards

How do we delete a property from an object?

We can delete a property from an object with the delete operator.

const spaceship = {
  'Fuel Type': 'Turbo Fuel',
  homePlanet: 'Earth',
  mission: 'Explore the universe' 
};
 
delete spaceship.mission;  // Removes the mission property]

78
New cards

What is a method?

When the data stored on an object is a function, we call that a

method. A property is what an object has, while a method is what an object does.

We can include methods in our object literals by creating ordinary, colon-separated key-value pairs. The key serves as our method’s name, while the value is an anonymous function expression.

const alienShip = {
  invade: function () { 
    console.log('Hello! We have come to dominate your planet. Instead of Earth, it shall be called New Xaculon.')
  }
};

With the new method syntax introduced in ES6, we can omit the colon and the function keyword.

const alienShip = {
  invade () { 
    console.log('Hello! We have come to dominate your planet. Instead of Earth, it shall be called New Xaculon.')
  }
};

Object methods are invoked by appending the object’s name with the dot operator, followed by the method name and parentheses:

alienShip.invade(); // Prints 'Hello! We have come to dominate your planet. Instead of Earth, it shall be called New Xaculon.'

79
New cards

What are nested objects?

In application code, objects are often nested — an object might have another object as a property, which in turn could have a property that’s an array of even more objects!

In our spaceship object, we want a crew object. This will contain all the crew members who do important work on the craft. Each of those crew members is an object in themselves. They have properties like name and degree, and they each have unique

methods based on their roles. We can also nest other objects in thespaceship, such as atelescope, or nest details about the spaceship’s computers inside a parentnanoelectronicsobject.

const spaceship = {
  telescope: {
    yearBuilt: 2018,
    model: '91031-XLT',
    focalLength: 2032 
  },
  crew: {
    captain: { 
      name: 'Sandra', 
      degree: 'Computer Engineering', 
      encourageTeam() { console.log('We got this!') } 
    }
  },
  engine: {
    model: 'Nimbus2000'
  },
  nanoelectronics: {
    computer: {
      terabytes: 100,
      monitors: 'HD'
    },
    'back-up': {
      battery: 'Lithium',
      terabytes: 50
    }
  }
}; 

We can chain operators to access nested properties. We’ll have to pay attention to which operator makes sense to use in each layer. It can be helpful to pretend you are the computer and evaluate each expression from left to right so that each operation starts to feel a little more manageable.

spaceship.nanoelectronics['back-up'].battery; // Returns 'Lithium'

In the preceding code:

  • First, the computer evaluates spaceship.nanoelectronics, which results in an object containing the back-up and computer objects.

  • We accessed the back-up object by appending ['back-up'].

  • The back-up object has a battery property, accessed with .battery, which returned the value stored there: 'Lithium'

80
New cards

Are objects passed by reference or by value?

Objects are passed by reference. This means when we pass a variable assigned to an object into a function as an argument, the computer interprets the parameter name as pointing to the space in memory holding that object. As a result, functions that change object properties actually mutate the object permanently (even when the object is assigned to aconstvariable).

const spaceship = {
  homePlanet : 'Earth',
  color : 'silver'
};
 
let paintIt = obj => {
  obj.color = 'glorious gold'
};
 
paintIt(spaceship);
 
spaceship.color // Returns 'glorious gold'
 

Our function paintIt() permanently changed the color of our spaceship object. However, reassignment of the spaceship variable wouldn’t work in the same way:

let spaceship = {
  homePlanet : 'Earth',
  color : 'red'
};
let tryReassignment = obj => {
  obj = {
    identified : false, 
    'transport type' : 'flying'
  }
  console.log(obj) // Prints { 'identified': false, 'transport type': 'flying' }
 
};
tryReassignment(spaceship) // The attempt at reassignment does not work.
spaceship // Still returns { homePlanet: 'Earth', color: 'red' };
 
spaceship = {
  identified : false, 
  'transport type': 'flying'
}; // Regular reassignment still works.

Let’s look at what happened in the code example:

  • We declared this spaceship object with let. This allowed us to reassign it to a new object with identified and 'transport type' properties with no problems.

  • When we tried the same thing using a function designed to reassign the object passed into it, the reassignment didn’t stick (even though calling console.log() on the object produced the expected result).

  • When we passed spaceship into that function, obj became a reference to the memory location of the spaceship object, but not to the spaceship variable. This is because the obj parameter of the tryReassignment() function is a variable in its own right. The body of tryReassignment() has no knowledge of the spaceship variable at all!

  • When we did the reassignment in the body of tryReassignment(), the obj variable came to refer to the memory location of the object { 'identified': false, 'transport type': 'flying' }, while the spaceship variable was completely unchanged from its earlier value.

81
New cards

How do we loop through objects?

JavaScript has given us an alternative solution for iterating through objects with for…in syntax.

for...in will execute a given block of code for each property in an object.

let spaceship = {
  crew: {
    captain: { 
      name: 'Lily', 
      degree: 'Computer Engineering', 
      cheerTeam() { console.log('You got this!') } 
    },
    'chief officer': { 
      name: 'Dan', 
      degree: 'Aerospace Engineering', 
      agree() { console.log('I agree, captain!') } 
    },
    medic: { 
      name: 'Clementine', 
      degree: 'Physics', 
      announce() { console.log(`Jets on!`) } },
    translator: {
      name: 'Shauna', 
      degree: 'Conservation Science', 
      powerFuel() { console.log('The tank is full!') } 
    }
  }
}; 

// for...in
for (let crewMember in spaceship.crew) {
  console.log(`${crewMember}: ${spaceship.crew[crewMember].name}`);
}

Our for...in will iterate through each property of the spaceship.crew object. In each iteration, the variable crewMember is set to one of spaceship.crew object’s keys, enabling us to log a list of crew members’ role and name.

82
New cards

What is the this keyword and how does it work in relation to objects?

Objects are collections of related data and functionality. We store that functionality in

methods on our objects:

const goat = {
  dietType: 'herbivore',
  makeSound() {
    console.log('baaa');
  }
};

In our goat object, we have a .makeSound() method. We can invoke the .makeSound() method on goat.

goat.makeSound(); // Prints baaa

Nice, we have a goat object that can print baaa to the console. Everything seems to be working fine. What if we wanted to add a new method to our goat object called .diet() that prints the goat object’s dietType?

const goat = {
  dietType: 'herbivore',
  makeSound() {
    console.log('baaa');
  },
  diet() {
    console.log(dietType);
  }
};
goat.diet(); 
// Output will be "ReferenceError: dietType is not defined"

That’s strange, why is dietType not defined even though it’s a property of goat? That’s because inside the scope of the .diet() method, we don’t automatically have access to other properties of the goat object.

Here’s where the this keyword comes to the rescue. If we change the.diet()method to usethis, then the .diet() method will work! :

const goat = {
  dietType: 'herbivore',
  makeSound() {
    console.log('baaa');
  },
  diet() {
    console.log(this.dietType);
  }
};

goat.diet(); 
// Output: herbivore

The this keyword references the calling object, which provides access to the calling object’s properties. In the preceding example, the calling object is goat, and by using this, we’re accessing the goat object itself, and then the dietType property of goat by using property dot notation.

83
New cards

Is it generally safe to use arrow functions for methods in conjunction with the this keyword?

If we use the this keyword in a method, then the value ofthisis the calling object. However, it becomes a bit more complicated when we start using arrow functions for methods. Take a look at the example below:

const goat = {
  dietType: 'herbivore',
  makeSound() {
    console.log('baaa');
  },
  diet: () => {
    console.log(this.dietType);
  }
};

goat.diet(); // Prints undefined

In the comment, note that goat.diet() would log undefined. So what happened? Notice that the .diet() method is defined using an arrow function.

Arrow functions inherently bind, or tie, an already defined this value to the function itself that is NOT the calling object.

The key takeaway from this example is to avoid using arrow functions when using this in a method!

84
New cards

Does JavaScript have privacy built in for objects?  

When discussing privacy in objects, we define it as the idea that only certain properties should be mutable or able to change in value.

Certain languages have privacy built in for objects, but JavaScript does not have this feature. Rather, JavaScript developers follow naming conventions that signal to other developers how to interact with a property. One common convention is to place an underscore (_) before the name of a property to mean that the property should not be altered. Here’s an example of using _ to prepend a property.

const bankAccount = {
  _amount: 1000
}

In the example above, the _amount is not intended to be directly manipulated.

Even so, it is still possible to reassign _amount:

bankAccount._amount = 1000000;

85
New cards

What are getters?

Getters are methods that get and return the internal properties of an object. But they can do more than just retrieve the value of a property! Let’s take a look at a getter method:

const person = {
  _firstName: 'John',
  _lastName: 'Doe',
  get fullName() {
    if (this._firstName && this._lastName){
      return `${this._firstName} ${this._lastName}`;
    } else {
      return 'Missing a first name or a last name.';
    }
  }
}

// To call the getter method: 
person.fullName; // 'John Doe'

Notice that in the getter method above:

  • We use the get keyword followed by a method name and a function body.

  • We use an if...else conditional to check if both _firstName and _lastName exist (by making sure they both return truthy values) and then return a different value depending on the result.

  • We can access the calling object’s internal properties using this. In fullName, we’re accessing both this._firstName and this._lastName.

  • In the last line, we call fullName on person. In general, getter methods do not need to be called with a set of parentheses. Syntactically, it looks like we’re accessing a property.

Now that we’ve gone over syntax, let’s discuss some notable advantages of using getter methods:

  • Getters can perform an action on the data when getting a property.

  • Getters can return different values using conditionals.

  • In a getter, we can access the properties of the calling object using this.

  • The functionality of our code is easier for other developers to understand.

NOTE: Another thing to keep in mind when using getter (and setter) methods is that properties cannot share the same name as the getter/setter function. If we do so, then calling the method will result in an infinite call stack error. One workaround is to add an underscore before the property name, like we did in the example above.

86
New cards

What are setters?

Along with getter methods, we can also create setter methods, which reassign values of existing properties within an object. Let’s see an example of a setter method:

const person = {
  _age: 37,
  set age(newAge){
    if (typeof newAge === 'number'){
      this._age = newAge;
    } else {
      console.log('You must assign a number to age');
    }
  }
};

Notice that in the example above:

  • We can perform a check for what value is being assigned to this._age.

  • When we use the setter method, only values that are numbers will be reassigned to this._age.

  • There are different outputs depending on what values are used to reassign this._age.

Then, to use the setter method:

person.age = 40;
console.log(person._age); // Logs: 40
person.age = '40'; // Logs: You must assign a number to age

Setter methods like age do not need to be called with a set of parentheses. Syntactically, it looks like we’re reassigning the value of a property.

Like getter methods, there are similar advantages to using setter methods that include checking input, performing actions on properties, and displaying a clear intention for how the object is supposed to be used. Nonetheless, even with a setter method, it is still possible to directly reassign properties. For example, in the example above, we can still set ._age directly:

person._age = 'forty-five'
console.log(person._age); // Prints forty-five

87
New cards

What are factory functions?

there are times when we want to create many instances of an object quickly. Here’s where factory functions come in. A real-world factory manufactures multiple copies of an item quickly and on a massive scale. A factory function is a function that returns an object and can be reused to make multiple object instances. Factory functions can also have parameters, allowing us to customize the object that gets returned.

Let’s say we wanted to create an object to represent monsters in JavaScript. There are many different types of monsters, and we could go about making each monster individually, but we can also use a factory function to make our lives easier. To achieve this diabolical plan of creating multiple monster objects, we can use a factory function that has parameters:

const monsterFactory = (name, age, energySource, catchPhrase) => {
  return { 
    name: name,
    age: age, 
    energySource: energySource,
    scare() {
      console.log(catchPhrase);
    } 
  }
};

In the preceding monsterFactory function, it takes four parameters and returns an object that has the properties: name, age, energySource, and the scare() method. To make an object that represents a specific monster like a ghost, we can call monsterFactory with the necessary arguments and assign the return value to a variable:

const ghost = monsterFactory('Ghouly', 251, 'ectoplasm', 'BOO!');
ghost.scare(); // 'BOO!'

Now we have a ghost object as a result of calling monsterFactory() with the needed arguments. With monsterFactory in place, we don’t have to create an object literal every time we need a new monster. Instead, we can invoke the monsterFactory function with the necessary arguments to make a monster for us!

88
New cards

What is property value shorthand?

ES6 introduced some new shortcuts for assigning properties to variables known as destructuring.

In the previous exercise, we created a factory function that helped us create

objects. We had to assign each property a key and value, even though the key name was the same as the parameter name we assigned to it. To remind ourselves, here’s a truncated version of the factory function:

const monsterFactory = (name, age) => {
  return { 
    name: name,
    age: age
  }
};

Imagine if we had to include more properties, that process would quickly become tedious! But we can use a destructuring technique, called property value shorthand, to save ourselves some keystrokes. We can use property value shorthand when the key and the variable passed in as the value share the same name. The following example works exactly the same as the previous:

const monsterFactory = (name, age) => {
  return { 
    name,
    age 
  }
};

Notice that we don’t have to repeat ourselves for property assignments!

89
New cards

What is destructured assignment?

We often want to extract key-value pairs from

objects and save them as variables. For example, the following object:

const vampire = {
  name: 'Dracula',
  residence: 'Transylvania',
  preferences: {
    day: 'stay inside',
    night: 'satisfy appetite'
  }
};

If we wanted to extract the residence property as a variable, we could use the following code:

const residence = vampire.residence; 
console.log(residence); // Prints 'Transylvania' 

However, we can also take advantage of a destructuring technique called destructured assignment to save ourselves some keystrokes. In destructured assignment, we create a variable with the name of an object’s key that is wrapped in curly braces { } and assign to it the object. Take a look at the example below:

const { residence } = vampire; 
console.log(residence); // Prints 'Transylvania'

Look back at the vampire object’s properties in the first code example. Then, in the example above, we declare a new variable residence that extracts the value of the residence property of vampire. When we log the value of residence to the console, 'Transylvania' is printed.

We can even use destructured assignment to grab nested properties of an object:

const { day } = vampire.preferences; 
console.log(day); // Prints 'stay inside'


90
New cards

What does Object.keys() do?

Object.keys() returns an array containing all the enumerable property names (keys) of an object.

General Format:

Object.keys(object)

Example:

const person = { name: "Alice", age: 25, city: "Paris" };
const keys = Object.keys(person);
console.log(keys); // ["name", "age", "city"]

Here, Object.keys(person) extracts all the property names from the person object and returns them as an array of strings.

91
New cards

What does Object.entries() do?

Object.entries() returns an array of a given object's key–value pairs, where each pair is itself an array [key, value].

General Format:

Object.entries(object)

Example:

const person = { name: "Alice", age: 25 };
const entries = Object.entries(person);
console.log(entries); // [["name", "Alice"], ["age", 25]]

Each property of the object becomes a small array, making it easy to loop through both keys and values.

92
New cards

What does Object.assign() do?

Object.assign() copies the properties from one or more source objects to a target object, returning the updated target object.

General Format:

Object.assign(target, source1, source2, ...)

Example:

const target = { a: 1 };
const source = { b: 2, c: 3 };
const result = Object.assign(target, source);
console.log(result); // { a: 1, b: 2, c: 3 }

Object.assign() merges the properties of source into target. If properties share the same key, later sources overwrite earlier ones.

93
New cards

What are classes?

JavaScript is an object-oriented programming (OOP) language we can use to model real-world items. Classes are a tool that developers use to produce similar objects quickly.

94
New cards

What is a constructor method?

Although there are a number of 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.

class Dog {
  constructor(name) {
    this.name = name;
    this.behavior = 0;
  }
}
  • Dog is the name of our class. By convention, we capitalize and PascalCase class names.

  • JavaScript will invoke the .constructor() method every time we create a new instance of our Dog class.

  • This .constructor() method accepts one argument, name.

  • Inside the .constructor() method, we use the this keyword. In the context of a class, this refers to an instance of that class. In the Dog class, we use this to set the value of the Dog instance’s name property to the name argument.

  • Under this.name, we create a property called behavior, which will keep track of the number of times a dog misbehaves. The behavior property is always initialized to zero.

95
New cards

What is a class 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 a new Dog instance
console.log(halley.name); // Log the name value saved to halley
// Output: 'Halley'

Below our Dog class, we use the new keyword to create an instance of our Dog class. Let’s consider the line of code step-by-step.

  • We create a new variable named halley that will store an instance of our Dog class.

  • We use the new keyword to generate a new instance of the Dog class. The new keyword calls the constructor, executes the code inside of it, and then returns the new instance.

  • We pass the 'Halley' string to the Dog constructor, which sets the name property to 'Halley'.

  • Finally, we log the value saved to the name key in our halley object, which logs 'Halley' to the console.

96
New cards

How do we call a class method?

Let’s use our new methods to access and manipulate data from Dog instances.

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');

In the example above, we create the Dog class, then create an instance, and save it to a variable named halley.

The syntax for calling methods and getters on an instance is the same as calling them on an object — append the instance with a period, then the property or method name. For methods, we must also include opening and closing parentheses.

Let’s take a moment to create two Dog instances and call our .incrementBehavior() method on one of them.

let nikko = new Dog('Nikko'); // Create dog named Nikko
nikko.incrementBehavior(); // Add 1 to nikko instance's behavior
let bradford = new Dog('Bradford'); // Create dog named Bradford
console.log(nikko.behavior); // Logs 1 to the console
console.log(bradford.behavior); // Logs 0 to the console

In the preceding example, we created two new Dog instances, nikko and bradford. Because we increment the behavior of our nikko instance, but not bradford, accessing nikko.behavior returns 1 and accessing bradford.behavior returns 0.

97
New cards

In terms of classes; what is inheritance?

When multiple classes share properties or methods, they become candidates for inheritance— a tool developers use to decrease the amount of code they need to write.

With inheritance, we can create a parent class (also known as a superclass) with properties and methods that multiple child classes (also known as subclasses) share. The child classes inherit the properties and methods from their parent class.

The diagram shown above shows the relationships we want to create between Animal, Cat, and Dog classes.

98
New cards

What do the extend and super keywords do in terms of classes?

We’ve abstracted the shared properties and methods of our Cat and Dog classes into a parent class called Animal here:

class Animal {
  constructor(name) {
    this._name = name;
    this._behavior = 0;
  }
    
  get name() {
    return this._name;
  }
  
  get behavior() {
    return this._behavior;
  }
    
  incrementBehavior() {
    this._behavior++;
  }
} 

Now that we have these shared properties and methods in the parent Animal class, we can extend them to the subclass, Cat.

class Cat extends Animal {
  constructor(name, usesLitter) {
    super(name);
    this._usesLitter = usesLitter;
  }
}

In the example above, we created a new class named Cat that extends the Animal class. Let’s pay special attention to our new keywords: extends and super.

  • The extends keyword makes the properties and methods of the Animal class available inside the Cat class.

  • The constructor, called when a new Cat object is created, accepts two arguments, name and usesLitter.

  • 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. When the Animal constructor runs, it sets this._name = name; for new Cat instances.

  • _usesLitter is a new property that is unique to the Cat class, so we set it in the Cat constructor.

Notice that we call super() on the first line of our constructor, then set the _usesLitter property on the second line. In a subclass constructor, we must always call the super() method before using the this keyword — if we do not, JavaScript will throw a reference error. To avoid reference errors, it is best practice to callsuper()on the first line of subclass constructors.

Below, we create a new Cat instance and call its name with the same syntax as we did with the Dog class:

const bryceCat = new Cat('Bryce', false); 
console.log(bryceCat.name); // output: Bryce

In the example above, we create a new instance of the Cat class, named bryceCat. We pass it 'Bryce' and false for our name and usesLitter arguments. When we call console.log(bryceCat._name), our program prints Bryce.

99
New cards

A child class inherits the properties and method of its parent class but is it possible for a child class to have its own properties and methods?

In addition to the inherited features, child classes can contain their own properties, getters, setters, and methods.

Below, we added a .usesLitter() getter to our Cat class. The syntax for creating getters, setters, and methods is the same as it is in any other class.

class Cat extends Animal {
  constructor(name, usesLitter) {
    super(name);
    this._usesLitter = usesLitter;
  }
    
  get usesLitter() {
    return this._usesLitter;
  }
}

In the example above, we create a .usesLitter() getter in the Cat class that returns the value saved to _usesLitter.

Compare the Cat class above to the one we created without inheritance:

class Cat {
  constructor(name, usesLitter) {
    this._name = name;
    this._usesLitter = usesLitter;
    this._behavior = 0;
  }
    
  get name() {
    return this._name;
  }
  
  get usesLitter() {
    return this._usesLitter;
  }
  
  get behavior() {
    return this._behavior;
  }   
  
  incrementBehavior() {
    this._behavior++;
  }
}

We decreased the number of lines required to create the Cat class by about half. Yes, it did require an extra class, Animal, which may make the reduction in the size of our Cat class seem pointless. However, the benefits — time saved, readability, efficiency — of inheritance grow as the number and size of our subclasses increase.

One benefit is that when we need to change a method or property that multiple classes share, we can update only the parent class, instead of needing to address each subclass.

Before we move past inheritance, take a moment to see how we would create an additional subclass, called Dog.

class Dog extends Animal {
  constructor(name) {
    super(name);
  }
}

This Dog class has access to the same properties, getters, setters, and methods as the Dog class we made without inheritance, and is a quarter the size!

100
New cards

What are static methods?

Sometimes, we want a class to have

methods

Preview: Docs Methods are object properties that contain functions.

that aren’t available in individual instances but can be called directly from the class.

Take the Date class, for example — we can both create Date instances to represent whatever date we want, and call static methods, like Date.now() which returns the current date, directly from the class. The .now() method is static, so it can be called directly from the class, but not from an instance of the class.

Let’s see how to use the static keyword to create a static method called generateName 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

.generateName() cannot be accessed from instances of the Animal class or instances of its subclasses:

const tyson = new Animal('Tyson'); 
tyson.generateName(); // TypeError

This example will result in an error, because a static method (.generateName()) cannot be called on an instance (tyson).