Arrow Functions: #
A cleaner and clearer way of writing functions in JavaScript. They make writing functions faster
const greet = (name) => {
return "Hello, " + name + "!";
};
console.log(greet("Asiqur"));
// Output: Hello, Asiqur!
Here the parameters are written inside parentheses and then the ‘=>’ symbol followed by ‘{ }’ braces. These functions can also be assigned to variables if we want.
Another benefit of these function is that we don’t need to specify the ‘return’ keyword to get an output. For e.g. -
const greetings = (text) => (text);
console.log(greetings("Well, Hello There!"));
// Output: Well, Hello There!
Here we don’t use the ‘{ }’ braces. Instead we use another pair of ‘( )’ and this tells the compiler that what’s inside the parentheses needs to be printed.
Another e.g.-
const forceEquation = (mass, acceleration) => (mass * acceleration);
console.log(forceEquation(3, 4));
// Output: 12
Template Literals: #
Although already discussed in the previous chapter of JavaScript, we come back to properly talk about Template Literals. Template Literals are special strings that are enclosed in backticks (` `) instead of quotes (' ‘) which help us in logging both string and any variable we want in a simpler way. (The backtick can be found above your tab key and to the left of the ‘1’ key on your keyboards. It is paired up with the tilde [~] symbol)
The variable that is to be logged out must be followed by ‘${ }’. For e.g.-
const favGame = (name) => (`My favourite game is ${name}!`);
console.log(favGame("Valorant"));
// Output: My favourite game is Valorant!
for… of loop: #
Loop which helps us in iterating over each item in a sequence such as a string or an array
const brokenTroop= "megaknight";
for (let letter of brokenTroop) {
console.log(letter);
}
/* Output:
m
e
g
a
k
n
i
g
h
t
*/
or for array:
const controllers = ["Clove","Brimstone", "Astra", "Viper", "Omen", "Harbor" ];
for (let agent of controllers) {
console.log(agent);
}
/*
Output:
Clove
Brimstone
Astra
Viper
Omen
Harbor
*/
for… in loop: #
The most ideal loop to iterate through objects (specifically to access the objects’ keys.)
const person = {
name: "Austin",
age: 29,
occupation: "musician"
}
for (let info in person) {
console.log(person[info]);
}
/*
Output:
Austin
29
musician
*/
Most Streamed Songs #
An example where we use both ‘for… of’ and ‘for… in’ loop:
const fiveMostStreamedSongs = [
{
title: "Blinding Lights",
artist: "The Weeknd",
streams: 4260000000
},
{
title: "Shape of You",
artist: "Ed Sheeran",
streams: 3901000000
},
{
title: "Someone You Loved",
artist: "Lewis Capaldi",
streams: 3413000000
},
{
title: "Sunflower",
artist: "Post Malone (feat. Swae Lee)",
streams: 3345000000
},
{
title: "As It Was",
artist: "Harry Styles",
streams: 3278000000
}
]
for (let song of fiveMostStreamedSongs){
console.log("\n");
for (let key in song){
console.log(song[key]);
}
}
/* Output -
Blinding Lights
The Weeknd
4260000000
Shape of You
Ed Sheeran
3901000000
Someone You Loved
Lewis Capaldi
3413000000
Sunflower
Post Malone (feat. Swae Lee)
3345000000
As It Was
Harry Styles
3278000000
*/
We can’t really use for… of in objects because they are not iterable in nature. They are in the form of ‘key-value’ pairs and we need their keys to access the information corresponding to the key. We have to use a bit more complex ways to access the information using for… of in objects. One way is listed below:
for (let value of Object.values(person)) {
console.log(value);
}
Here, the .values() is what lets us get the direct values without using the keys. It’s still better to use for… in loop as it is simpler and cleaner.
Spread Operator: #
The spread operators helps us in concatenating arrays and other collection of items to use in other places. All we gotta do is put three dots before the name of the collection of items and voila!
sentinels = ["Sage", "Killjoy", "Deadlock", "Cypher", "Chamber", "Veto"];
duelists = ["Reyna", "Yoru", "Jett", "Waylay", "Neon", "Raze","Iso", "Phoenix"];
const agents = [...sentinels, ...duelists];
console.log(agents);
/*
Output:
["Sage", "Killjoy",
"Deadlock", "Cypher",
"Chamber", "Veto",
"Reyna","Yoru",
"Jett","Waylay",
"Neon","Raze",
"Iso","Phoenix"
]
*/
Rest Operator: #
The ‘packing’ of the elements can be done using the ‘Rest’ operator. If we use those same three dots in a certain way (generally inside functions), we can pack them. This is especially useful when we are dealing with functions wherein, we don’t really know how many arguments it should take. For e.g.-
const packGroceries = (...items) => {
return items; }
const packedGroceries = packGroceries("apples", "bananas", "milk");
const morePackedGroceries = packGroceries("eggs", "bread"); console.log(packedGroceries);
console.log(morePackedGroceries);
/* Output:
[ 'apples', 'bananas', 'milk' ]
[ 'eggs', 'bread' ]
*/
The elements are automatically packed into an array. Here, the data structure which makes the most sense to put in the objects is an array as it is ordered, has flexible length and is index-based.
Using both spread and rest operators #
const planVacation = (destinationOne, destinationTwo,...otherDestinations) => {
return [destinationOne, destinationTwo, ...otherDestinations];
};
const vacationPlan = planVacation(
"Paris",
"Rome",
"Tokyo",
"Bali"
);
console.log(vacationPlan);
//Output: ['Paris','Rome','Tokyo','Bali']
Tip! #
Always keep in mind that the three dots when used as function parameters, are acting as the rest operator and will club the elements into an array and when used in function call will expand the array into smaller objects.
Exercise: #
[[https://www.codedex.io/home]] has given an amazing exercise to practice everything we have learned up until now.
Define a goodreadsInfo object with the following structure:
const goodreadsInfo = {
currentlyReading: [
{
title: "",
author: ""
}
],
wantToRead: [
{
title: "",
author: ""
}
]
}
Define an addNewBooks() arrow function. This function should return a new array that includes all items from books along with any items from the additionalBookObjects array.
Then, use this function on at least one of the lists from the goodreadsInfo object, like so:
goodreadsInfo.currentlyReading = addNewBooks(goodreadsInfo.currentlyReading, /* new books here */
Define a showGoodreadsInfo() function that accepts a single info parameter.
Inside, create two variables representing the reading list arrays from the info parameter.
Then, use a combination of console.log() statements, for...of loops, and template literals to output our reading lists to the console.
Solution #
const goodreadsInfo = {
currentlyReading: [
{
title: "Death at Morning House",
author: "Someone"
}
],
wantToRead: [
{
title: "The Midnight Feast",
author: "Someone"
}
]
};
const addNewBooks = (books, ...additionalBookObjects) => {
const newArray = [...books, ...additionalBookObjects];
return newArray;
};
goodreadsInfo.currentlyReading = addNewBooks(
goodreadsInfo.currentlyReading,
{ title: "Harry Potter", author: "J.K. Rowling" }
);
const showGoodreadsInfo = (info) => {
const currentlyReading = info.currentlyReading;
const wantToRead = info.wantToRead;
console.log("📖 Currently Reading:");
for (const book of currentlyReading) {
console.log(`- "${book.title}" by ${book.author}`);
}
console.log("\n📚 Want to Read:");
for (const book of wantToRead) {
console.log(`- "${book.title}" by ${book.author}`);
}
};
showGoodreadsInfo(goodreadsInfo);
Callbacks #
Functions which are passed as arguments in parent functions and are called under some conditions like on-click.
We will talk about asynchronous events now. These are events that take place on the browser without stopping the other code. JavaScript code is run from top to bottom of the file. The next line executes only after the previous one is done executing. But asynchronous events are different as they let the code after it run while they perform their own task.
An event after pressing a button or waiting for data to be fetched from an external source can be examples of asynchronous events.
Let’s see an example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Subscribe Button</title>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<div class="subscribe-container">
<button id="subscribeBtn">Subscribe</button>
<p id="message" class="hidden">Thank you for subscribing!</p>
</div>
<script src="index.js"></script>
</body>
</html>
body {
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #f0f0f0;
}
.subscribe-container {
text-align: center;
}
#subscribeBtn {
padding: 10px 20px;
font-size: 16px;
cursor: pointer;
background-color: #007bff;
color: white;
border: none;
border-radius: 5px;
transition: background-color 0.3s;
}
#subscribeBtn:hover {
background-color: #0056b3;
}
#message {
margin-top: 20px;
font-size: 18px;
color: #28a745;
}
.hidden {
display: none;
}
const subscribeBtn = document.getElementById("subscribeBtn");
const message = document.getElementById("message");
subscribeBtn.addEventListener("click", () => {
subscribeBtn.innerText = "Subscribed";
message.classList.remove("hidden");
setTimeout(() => message.classList.add("hidden"), 3000);
});
Focusing on the JS, we have an on-press event which changes the text inside the button and shows a message. The setTimeout() function hides the text again after 3000 ms or 3 seconds.
Promise 💫 #
I made a promise~ 🎶 oh sorry. Promises in JS are another great example of Asynchronous tools. They are in-built objects which helps us know if the operation we performed was a success or no. They have 3 states -
- A “pending” state for an unfinished operation (default).
- A “fulfilled” state for a successful operation.
- A “rejected” state for an unsuccessful operation.
They help in handling errors or fetching data. We pass a callback function inside the promise with two parameters - resolve and reject. Resolve for a successful operation and reject for an unsuccessful one. Here, we don’t invoke the callback directly. It’s instead done by the promise which we define.
Let’s see an example-
function randomNumberPromise() {
return new Promise((resolve, reject) => { //syntax of declaring a promise
const randomNumber = Math.floor(Math.random() * 10) + 1;
if (randomNumber < 5) {
resolve();
} else {
reject("Rejected");
}
});
}
const generateBtn = document.getElementById("generateButton");
generateBtn.addEventListener("click", randomNumberPromise);
Here, the event is a success if the random number is smaller than 5 and it fails otherwise.
Callback Hell #
Well we might want that a task is executed after several tasks are done executing. That means, we will need multiple callbacks inside… more callbacks? Using this example, let’s try to understand this -
function prepareOrder(callback) {
const result = "Preparing order 🧑🍳";
callback(result);
}
function serveOrder(result, callback) {
const result2 = `${result}, and now serving. Enjoy! 🍲`;
callback(result2)
}
// Calling the operations
prepareOrder(function(result) {
serveOrder(result, function(result2) {
console.log(result2);
});
});
Here we use callback(result). This acts like a doorway to the next step. What that means is that the next step’s execution is dependent on the execution of the step before. Callback is telling us that this will be used by something else later. Which we see in the next function. We are using another function which calls back the first result. Then again, the second result is inside the callback, meaning it will be used in the future again. Which we finally see at the end. We pass both the results as callback and finally log both of them together.
Now, we can make this more efficient with the use of ⭐Promise⭐ (and also something called as .then() and .catch() ).
Promise Chaining #
Using the same example -
function prepareOrder() {
return new Promise((resolve) => {
const result = "Preparing order 🧑🍳";
resolve(result);
})
}
function serveOrder(result) {
return new Promise((resolve) => {
const result2 = `${result}, and now serving. Enjoy! 🍲`;
resolve(result2);
})
}
prepareOrder()
.then((result) => serveOrder(result))
.then((result2) => {
console.log(result2)
})
.catch((error) => {
console.log("Error:", error);
})
Here the first two loops are very similar, the only difference being the promise. This makes the work very easy for us later. We get the values of result and result2 after successfully resolving the two promises. Then we use .then() function
- This helps in chaining multiple promises.
- The .catch() at the end will catch any error in any promises or any .then() function. YES, one function for the entire chain.
- The next then() will wait for the previous .then(), only if .then((whatever) has => has another promise at the RHS. .then() only waits for promises, otherwise they will run. So -
If you return a Promise, the chain waits.
If you don’t return, the next.then()runs immediately.
The .fetch() and .catch() is also used with using API’s and converting stuff to .json data type first and then using the data for our code -
fetch("https://dog.ceo/api/breeds/image/random")
.then((response) => response.json())
.then((data) => console.log(data))
.catch((error) => console.error()
async and await #
More concise way of writing promises. It’s not important that we use these only and not the previous method but it’s good to know these!
function getSomeDataWithChain() {
fetch(someData)
.then((response) => response.json())
.then((data) => data)
.catch((error) => console.log("Something went wrong. 😦"));
}
async function getSomeDataWithAsync() {
const response = await fetch(someData);
if (response.ok === false) {
throw new Error("Something went wrong. 😦");
}
const data = await response.json();
}
These are two different ways of writing the same thing. async is written before the function and await is written before performing some task so that the next task only happens after the completion of the previous promise. The completion might result in a failure or success. .ok checks whether the data we fetched is successfully fetched without any problems.
Basically, instead of writing catch() to check errors, we use .ok to check for errors.
Music to my ears #
Well we finally have this wrapped up. How about we try and make something with our newly acquired knowledge so that we retain some if not all of it? Sounds like m– Well anyways I was thinking maybe something music related considering I am listening to music like 24/7.
Well I have been using Spotify since forever so I HAD to use it’s API. API - Application programming Interface is some piece of code that allows 2 programs to communicate. Famous apps and services provide their API so that we can use them to create cool projects! (some API’s are paid and some have limited usage so keep that in mind!)
I will be making an Album Finder as well as React. Though I haven’t really learnt how to use React, I will be taking help from the internet for that. React is an extension of JS which let’s us create re-usable components that we can use for efficient Development.
The code of that is on my Git-Hub so feel free to check it out. Also big shoutout to CodeDex for helping me learn and build this 💗