Time: ⏰ 1 hour and 15 minutes ⏰
Slides:
By the end of this lesson, fellows will be able to:
- Understand the inner workings of higher-order methods.
- Learn how to use higher-order methods in JavaScript.
- Gain practical experience in applying higher-order methods to solve coding challenges and real-world problems.
🎉 Greeting:
Good afternoon everyone! Glad you could make it to this review over Higher-Order Methods in JavaScript. I'm excited to have you all here today!
💡 Explain power of higher-order methods:
Today, we have an exciting opportunity to dive into the world of higher-order methods in JavaScript. These methods are incredibly powerful tools that can greatly simplify and expedite your coding process. They allow us to accomplish complex tasks with elegance and efficiency, saving us valuable time that would otherwise be spent on manual and repetitive coding.
⏱️ Jumping right in:
We're going to jump right into talking about higher-order methods so that we can have ample time for hands-on practice and problem-solving. Let's make the most of this time.
🔥 Warm-up code challenge:
Before we begin, let's kickstart our learning with a warm-up challenge. Take a look at the code snippet on the screen. We have an array of objects, and our goal is to filter out the objects that are currently in stock and place them in the inStockProducts array. Let's think about how we can approach this by looping through the array of objects.
const products = [
{ name: 'iPhone', price: 999, inStock: true },
{ name: 'Laptop', price: 1499, inStock: true },
{ name: 'Headphones', price: 199, inStock: false },
{ name: 'Smartwatch', price: 299, inStock: true },
{ name: 'Tablet', price: 799, inStock: false },
];
Students View
const inStockProducts = [];
for (let i = 0; i < products.length; i++) {
}
// Filter out products that are in stock
const inStockProducts = [];
for (let i = 0; i < products.length; i++) {
if (products[i].inStock) {
inStockProducts.push(products[i]);
}
}
console.log('In stock products:', inStockProducts);
/// this warm up will allow for the following meta skills to be activated:
/// 1. Array Iteration: Traverse an array and perform operations on each item.
/// 2. Indexing and Accessing: Retrieve specific elements from an array using indices.
/// 3. Object Access: Access object properties and values using dot or bracket notation.
/// 4. Nested Data Structures: Navigate and access elements in nested data structures.
Transition:
Now, the code we just saw is a valid solution for filtering out the products that are in stock. However, JavaScript provides us with a more concise and efficient way of achieving the same result. It's all about leveraging the power of higher-order methods. Let's take a look at how JavaScript thinks about this problem:
const inStockProducts = products.filter(product => product.inStock);
Wow, so concise. If we think about programming, it's communication between you and your computer about what you want to get done. The shorter that communication, the better.
Before we jump into the details of the syntax, let's talk about this larger concept under which this all falls, which are higher-order methods. In today's review, we will:
Learn what exactly we mean when we talk about "higher order." Understand the inner workings of higher-order methods. This included callbacks and what that all means. Explore how to use higher-order methods in practical coding sessions. We will do this by working with a few commonly used higher-order methods: filter, reduce, and map.
Let's first start with the term "higher order," which originates from mathematics. In programming, it refers to a function that takes another function as an argument, often known as a callback function. The higher order function serves as the invoker or summoner of the callback.
Here's an example using the filter function:
products.filter(product => product.inStock)
Show the 3 different ways of seeing a function
/// Using Arrow Function:
products.filter(product => product.inStock)
// Using Separate Function:
function filterInStock(product) {
return product.inStock;
}
products.filter(filterInStock);
// Using Embedded Anonymous Function:
products.filter(function(product) {
return product.inStock;
});
In this example, filter is the higher order function because it can accept another function (the arrow function product => product.inStock) as an argument. The callback function, in this case, provides the filtering logic.
If someone were to ask, "Hey, arrow function, where did you come from?" it would point back to the "higher order" function, which is filter. filter is the one that "summoned" or invoked the arrow function to perform the filtering task.
💡 Higher-order functions are a powerful concept in JavaScript, as they can accept both variables and functions as arguments. This allows for greater flexibility and functionality in our code. Remember, anyone can create their own higher-order functions. Let's explore an example together:
function greet(name) {
console.log(`Hello, ${name}!`);
}
function higherOrderFunction(callback) {
const name = "John";
callback(name);
}
higherOrderFunction(greet);
Take a few moments to examine the code snippet on the screen. Answer in the chat box or out loud:
- How the higher-order function higherOrderFunction is implemented?
- How does it invokes the callback function greet with the name parameter?
In today's discussion, we'll focus on a specific type of higher-order functions that are already provided for us in JavaScript. These functions are specifically designed to work with arrays and are part of the array class: map(), filter(), and reduce(). These methods offer powerful ways to transform, filter, and aggregate array data.
🔍 Let's engage in an interactive session to explore the map() method in JavaScript. We'll start by examining some code and discussing our observations. Take a moment to carefully observe the following code snippet:
const numbers = [1, 2, 3, 4, 5];
const doubledNumbers = numbers.map(num => num * 2);
console.log(doubledNumbers);
Please share your observations and insights about the code. What do you see happening?
Fellows possible answers:
1. "The code declares an array called numbers containing a sequence of numeric values."
2. "The map() method is called on the numbers array."
3. "A callback function is passed to the map() method."
4. "The callback function is an arrow function that takes a parameter called num."
5. "Inside the callback function, each element of the numbers array is multiplied by 2."
6. "The map() method returns a new array with the transformed values."
7. "The new array, doubledNumbers, is logged to the console."
I would like to explain this process through looking at another code snippeet that I will explain as we walk through:
const numbers = {
data: [1, 2, 3, 4, 5],
map(callback) {
const result = [];
for (let i = 0; i < this.data.length; i++) {
result.push(callback(this.data[i]));
}
return result;
}
};
const doubledNumbers = numbers.map(num => num * 2);
console.log(doubledNumbers); // Output: [2, 4, 6, 8, 10]
Let's go through a coding activity together:
const names = ['Alice', 'Bob', 'Charlie', 'Dave'];
// TODO: Use the map() method to transform the names into greetings
// Expected output: ['Hello, Alice!', 'Hello, Bob!', 'Hello, Charlie!', 'Hello, Dave!']
use the map under the hood to guide this problem
const names = {
data: ['Alice', 'Bob', 'Charlie', 'Dave'],
map(callback) {
const result = [];
for (let i = 0; i < this.data.length; i++) {
result.push(callback(this.data[i]));
}
return result;
}
};
const greetings = names.map(name => `Hello, ${name}!`);
console.log(greetings); // Output: ['Hello, Alice!', 'Hello, Bob!', 'Hello, Charlie!', 'Hello, Dave!']
Next give them a little more challenging problem:
const numbers = [2, 4, 6, 8, 10];
// TODO: Use the map() method to transform the numbers by squaring them
console.log(squaredNumbers);
// Expected output: [4, 16, 36, 64, 100]
Under the hood:
const numbers = {
data: [2, 4, 6, 8, 10],
map(callback) {
const result = [];
for (let i = 0; i < this.data.length; i++) {
result.push(callback(this.data[i]));
}
return result;
}
};
const squaredNumbers = numbers.map(number => number ** 2);
console.log(squaredNumbers); // Output: [4, 16, 36, 64, 100]
const numbers = {
data: [2, 4, 6, 8, 10],
reduce(callback, initial) {
let accumulator = initial;
for (let i = 0; i < this.data.length; i++) {
accumulator = callback(accumulator, this.data[i]);
}
return accumulator;
},
};
const sum = numbers.reduce((accumulator, number) => accumulator + number, 0);
console.log(sum); // Output: 30