MAIN POINTS
Destructuring, spread operator, template literals, ternaries
Map, filter, reduce, sort
Asynchronous JavaScript
OTHER KEYPOINTS
JavaScript string Methods (Include Reference link)
Use destructure when we need to basically get some data out of object or out of an array / get data from api.
This is a part example of API.
const data = [
{
id: 5,
title: "A Game of Thrones",
publicationDate: "1996-08-01",
author: "George R. R. Martin",
genres: ["fantasy", "high-fantasy", "novel", "fantasy fiction"],
hasMovieAdaptation: true,
pages: 835,
translations: {
korean: "왕좌의 게임",
polish: "Gra o tron",
portuguese: "A Guerra dos Tronos",
spanish: "Juego de tronos",
},
reviews: {
goodreads: {
rating: 4.44,
ratingsCount: 2295233,
reviewsCount: 59058,
},
librarything: {
rating: 4.36,
ratingsCount: 38358,
reviewsCount: 1095,
},
},
},
];
A cumbersome way:
function getBook(id) {
return data.find((d) => d.id === id);
}
const book = getBook(5);
// get title and author from book object
const title = book.title;
const author = book.author;
// get the primary and secondary genre from genres array
const primaryGenre = genres[0];
const secondaryGenre = genres[1];
Using destructure
const { title, author, pages, publication } = book;
console.log(title, author);
// Same output: A Game of Thrones George R. R. Martin
const [primaryGenre, secondaryGenre] = genres;
console.log(primaryGenre, secondaryGenre);
// Same output: fantasy high-fantasy
Rest Operator is a feature in JavaScript that allows you to represent an indefinite number of arguments as an array.
The remaining elements of the genres array are gathered into a new array called otherGenres using the rest operator (…).
const [primaryGenre, secondaryGenre, ...otherGenres] = genres;
console.log(primaryGenre, secondaryGenre, otherGenres);
// fantasy high-fantasy [ 'novel', 'fantasy fiction' ]
Requirement 1: create a new array containing all the current genres and then add another one in the beginning/end.
// const newGenres = [genres, "epic fantasy"];
// [ [ 'fantasy', 'high-fantasy', 'novel', 'fantasy fiction' ], 'epic fantasy' ]
const newGenres = [...genres, "epic fantasy"];
[ 'fantasy', 'high-fantasy', 'novel', 'fantasy fiction', 'epic fantasy' ]
Requirement 2: add new properties and update existing ones for objects.
// const updatedBook = { book, moviePublicationDate: "2001-12-19" };
const updatedBook = {
...book,
// adding a new property
moviePublicationDate: "2001-12-19",
// overwriting an existing property
pages: 1210,
};
Template literals provide an easy way to interpolate variables and expressions into strings.
const summary = `${title}, a ${pages}-page long book, was written by ${author} and published in ${publicationDate.split("-"[0])}`;
summary;
// A Game of Thrones, a 835-page long book, was written by George R. R. Martin and published in 1996,08,01
Ternary operator: condition ? expression1 : expression2
The condition is true, expression1 is the result of the ternary operation. If the condition is false, expression2 becomes the result.
const pagesRange =
pages > 1000
? "condition is true, page is over a thousand"
: "less than 1000";
pagesRange; // less than 1000
(parameter1, parameter2, …) => {
// Function body
// Return statement (optional)
}
// function declaration
function getYear(str) {
return str.split("-"[0]);
}
// function expression
const getYear = (str) => str.split("-")[0];
// in function, we have multiline code, we have to add return
const getYear = (str) => {
// Multiline code
// ...
return str.split("-")[0];
};
this
?Arrow functions have a few characteristics worth noting:**
Lexical this
binding: Arrow functions do not bind their own this
value but instead inherit it from the surrounding context. This can be advantageous when dealing with callback functions or nested functions where the value of this
would change with traditional function expressions.
No arguments object: Arrow functions do not have their own arguments object. If you need to access the arguments passed to an arrow function, you can use the rest parameter syntax (…args) to gather them into an array.
Cannot be used as constructors: Arrow functions do not have a prototype property and cannot be used as constructors to create new objects.
Implicit return: If the function body consists of a single expression, the arrow function will automatically return the value of that expression without the need for an explicit return statement.
The logical AND operator (&&) evaluates two operands and returns true if both operands are truthy. If the first operand is falsy, it short-circuits and immediately returns that falsy value without evaluating the second operand. Otherwise, it evaluates and returns the second operand.
Truth table for logical AND (&&):
Operand 1 | Operand 2 | Result |
---|---|---|
true | true | true |
true | false | false |
false | true | false |
false | false | false |
console.log(true && "Some String"); //Some String
console.log(false && "Some String"); //false
console.log(hasMovieAdaptation && "This book has a movie"); //false
console.log ("miluo" && "some string"); //Some string
console.log(0 && "Some string"); //0
The logical OR operator (||) evaluates two operands and returns true if either of the operands is truthy. If the first operand is truthy, it short-circuits and immediately returns that truthy value without evaluating the second operand. Otherwise, it evaluates and returns the second operand.
Truth table for logical OR (||):
Operand 1 | Operand 2 | Result |
---|---|---|
true | true | true |
true | false | true |
false | true | true |
false | false | false |
console.log(true || "some string"); // true
console.log(false || "some string"); // some string
console.log(book.translations.spanish); // undefined
const spanishTranslation = book.translations.spanish || "NOT TRANSLATED";
spanishTranslation; // NOT TRANSLATED
console.log(book.reviews.librarything.reviewsCount);
const countwrong = book.reviews.librarything.reviewsCount || "no data";
countwrong; // no data
// 0, no data,wrong
const count = book.reviews.librarything.reviewsCount ?? "no data";count; // 0
// right
The nullish coalescing operator (??) is used to provide a default value when the left-hand side operand is null or undefined (not when 0 or empty atring). If the left-hand side is neither null nor undefined, the operator returns the left-hand side value.
Truth table for nullish coalescing operator (??):
Operand 1 | Operand 2 | Result |
---|---|---|
true | true | true |
true | false | true |
false | true | false |
false | false | (Operand 2) |
truthy value / falsy value: 0, ‘’, null, undefined
EXAMPLE:
const username = null;
const defaultName = "Guest";
const result = username ?? defaultName;
console.log(result); // Output: "Guest"
const username = false; // or 0 or ''
const defaultName = "Guest";
const result = username ?? defaultName;
console.log(result); // Output: false
NOTE: Logical operators in JavaScript employ short-circuiting.
Optional chaining allows you to safely access nested properties or methods of an object without worrying about encountering a TypeError if any intermediate property or method is null or undefined.
The optional chaining operator is denoted by (?) placed before the dot operator (.). It can be used to chain together multiple property or method accesses.
function getTotalReviewCount(book) {
const goodread = book.reviews?.goodreads?.reviewsCount ?? 0;
// const librarything = book.reviews.librarything.reviewsCount;
const librarything = book.reviews?.librarything?.reviewsCount ?? 0;
librarything; // wrong -> undefined -> 0
return goodread + librarything;
}
console.log(getTotalReviewCount(book)); // NaN -> 49701
⬆ back to top
The map method is used to create a new array by transforming each element of an existing array based on a provided callback function. The callback function takes three arguments: the current element, the index, and the original array. It returns a new value that will be added to the resulting array.
Simple example
const arr = [1, 2, 3, 4];
console.log(arr);
console.log(arr.map((el) => el + 1));
// [ 1, 2, 3, 4 ]
// [ 2, 3, 4, 5 ]
The filter method is used to create a new array containing only the elements from an existing array that satisfy a certain condition specified by a callback function. The callback function takes three arguments: the current element, the index, and the original array. It returns true or false to determine if an element should be included in the resulting array.
const longBooksWithMovies = books
.filter((book) => book.pages > 500)
.filter((book) => book.hasMovieAdaptation);
longBooksWithMovies;
const adventureBooks = books
.filter((books) => books.genres.includes("adventure"))
.map((book) => book.title);
adventureBooks;
The reduce method is used to reduce an array to a single value by applying a reducer function to each element of the array. The reducer function takes four arguments: the accumulator, the current element, the index, and the original array. The accumulator stores the intermediate result during the reduction process.
const pagesAllBooks = books.reduce((sum, book) => sum + book.pages, 0);
pagesAllBooks; // 3227
The sort method is used to sort the elements of an array in place and return the sorted array. By default, the elements are sorted in ascending order based on their string representations. However, you can provide a compare function as an argument to define a custom sorting order.
const arr = [3, 7, 1, 9, 6];
// const sorted = arr.sort((a, b) => b - a); // in a descending order
const sorted = arr.slice().sort((a, b) => a - b); // in an ascending order
sorted;
arr;
// not functional method, a method that mutates the original array ×
// slice() copy original array
const sortedByPages = books.slice().sort((a, b) => b.pages - a.pages);
sortedByPages;
About slice()
// 1) Add book object to array
const newBook = {
id: 6,
title: "Harry Potter and the Chamber of Secrets",
author: "J. K. Rowling",
};
const booksAfterAdd = [...books, newBook];
booksAfterAdd;
// 2) Delete book object from array
const booksAfterDelete = booksAfterAdd.filter((book) => book.id !== 3);
booksAfterDelete;
// 3) Update book object in the array
const booksAfterUpdate = booksAfterDelete.map((book) =>
book.id === 1 ? { ...book, pages: 1210 } : book
);
booksAfterUpdate;
Application of this part ()
link: https://github.com/luomi16/Awesome-simple-react/blob/main/3-Travel-List/src/App.js
function handleAddItems(item) {
// cannot change original array
setItems((items) => [...items, item]);
}
function handleDeleteItem(id) {
// https://github.com/luomi16/My-Blog/blob/main/JS/Essential-JavaScript-Fundamentals.md#working-with-lmmutable-arrays
setItems((items) => items.filter((item) => item.id !== id));
}
function handleToggleItem(id) {
setItems((item) =>
items.map((item) =>
item.id === id ? { ...item, packed: !item.packed } : item
)
);
}
(JavaScript functions are executed in the sequence they are called. Not in the sequence they are defined.)
Sequence Control: do a calculation, and then display the result.
function myDisplayer(some) {
document.getElementById("demo").innerHTML = some;
}
function myCalculator(num1, num2, myCallback) {
let sum = num1 + num2;
myCallback(sum);
}
myCalculator(5, 5, myDisplayer); // not to use parenthesis. myDisplayer()
In the example above, myDisplayer
is a called a callback function. It is passed to myCalculator()
as an argument.
EXAMPLE: setTimeout()
When using the JavaScript function setTimeout()
, you can specify a callback function to be executed on time-out (在指定时间后调用函数或计算表达式)
// passing the name of a function as an argument to another function
setTimeout(myFunction, 3000);
function myFunction() {
document.getElementById("demo").innerHTML = "I love You !!";
}
// pass a whole function
setTimeout(function() { myFunction("I love You !!!"); }, 3000);
function myFunction(value) {
document.getElementById("demo").innerHTML = value;
}
Functions running in parallel with other functions are called asynchronous
In the real world, callbacks are most often used with asynchronous functions.
Callback Alternatives
With asynchronous programming, JavaScript programs can start long-running tasks, and continue running other tasks in parallel.
But, asynchronous programs are difficult to write and difficult to debug.
Because of this, most modern asynchronous JavaScript methods don’t use callbacks. Instead, in JavaScript, asynchronous programming is solved using Promises instead.
“Producing code” is code that can take some time
“Consuming code” is code that must wait for the result
A Promise is a JavaScript object that links producing code and consuming code
fetch("https://jsonplaceholder.typicode.com/todos")
.then((res) => res.json())
.then((data) => console.log(data));
console.log("baby");
The usage of Fetch
async function getTodos() {
const res = await fetch("https://jsonplaceholder.typicode.com/todos");
const data = await res.json();
console.log(data);
return data;
}
getTodos();
console.log("baby");
⬆ back to top
JavaScript String Methods (Include Reference link)
slice()
extracts a part of a string and returns the extracted part in a new string.
The method takes 2 parameters: start position, and end position (end not included).
Example1
Slice out a portion of a string from position 7 to position 13: (JavaScript counts positions from zero.)
let text = "Apple, Banana, Kiwi";
let part = text.slice(7, 13);
console.log(part); // Banana
If you just pass into single argument, it is start position.
About indexOf()
Example2
const word = "pot";
const target = "potato";
console.log(target.indexOf(word)); // 0
console.log(target.slice(word.length)); // ato
The trim()
method removes whitespace from both sides of a string
let text1 = " Hello World! ";
let text2 = text1.trim();
console.log(text2); // Hello World!
A string
can be converted to an array
with the split()
method:
extract the year from a string formatted as “YYYY-MM-DD” by splitting the string
const getYear = (str) => str.split("-")[0]; // 2023-6-20 -> [2023, 6, 20] OUTPUT: 2023