Destructuring
we can destructure an array or object by reassigning their values using a function or by creating a new array.
ways of destructuring
const arr = [2, 3, 4];
const [x, y, z] = arr;
console.log(x, y, z);
we can also switch variables
const restaurant = {
name: 'Classico Italiano',
location: 'Via Angelo Tavanti 23, Firenze, Italy',
categories: ['Italian', 'Pizzeria', 'Vegetarian', 'Organic'],
starterMenu: ['Focaccia', 'Bruschetta', 'Garlic Bread', 'Caprese Salad'],
mainMenu: ['Pizza', 'Pasta', 'Risotto'],
}
let [main, , secondary] = restaurant.categories;
console.log(main, secondary);
//Italian, Vegetarian
[main, secondary] = [secondary, main];
console.log(main, secondary);
// Vegetarian, Italian
we can also use a function to capture the variable we want before assigning them to a new value
const restaurant = {
name: 'Classico Italiano',
location: 'Via Angelo Tavanti 23, Firenze, Italy',
categories: ['Italian', 'Pizzeria', 'Vegetarian', 'Organic'],
starterMenu: ['Focaccia', 'Bruschetta', 'Garlic Bread', 'Caprese Salad'],
mainMenu: ['Pizza', 'Pasta', 'Risotto'],
order: function (starterIndex, mainIndex) {
return [this.starterMenu[starterIndex], this.mainMenu[mainIndex]];
},
const [starter, mainCourse] = restaurant.order(2, 0);
console.log(starter, mainCourse);
//Garlic bread, Pizza
const nested = [2, 4, [5, 6]]; //array inside array = nested
const [i, , [j, k]] = nested;
console.log(i, j, k); //we need to destructure within the destructure
//2,5,6
const [p = 1, q = 1, r = 1] = [8, 9];
console.log(p, q, r);
1,1,1
Destructuring objects
destructuring objects is extremely useful when it comes to using API as it comes in obj form.
const restaurant = {
name: 'Classico Italiano',
location: 'Via Angelo Tavanti 23, Firenze, Italy',
categories: ['Italian', 'Pizzeria', 'Vegetarian', 'Organic'],
starterMenu: ['Focaccia', 'Bruschetta', 'Garlic Bread', 'Caprese Salad'],
mainMenu: ['Pizza', 'Pasta', 'Risotto'],
}
const { name, openingHours, categories } = restaurant;
//creates 3 brandnew variables (name, opening hours, categories)
console.log(name, openingHours, categories);
// Classico Italiano {thu: {…}, fri: {…}, sat: {…}}fri: {open: 11, close: 23}sat: {open: 0, close: 24}thu: {open: 12, close: 22}[[Prototype]]: Object (4) ['Italian', 'Pizzeria', 'Vegetarian', 'Organic']
we can also assign new names to the new variables by doing this
const {
name: restaurantName,
openingHours: hours,
categories: tags,
} = restaurant;
It's useful to set defaults if we are retrieving data from an external source and we don't know what it looks like instead of having 'hard data' where we have it in the code intead of using a json or api.
const { menu = [], starterMenu: starters = [] } = restaurant;
console.log(menu, starters);// [] (4) ['Focaccia', 'Bruschetta', 'Garlic Bread', 'Caprese Salad']
- Mutating variables (similar to switching variables in array)
let a = 111;
let b = 999;
const obj = { a: 23, b: 7, c: 14 };
({ a, b } = obj); //we need to wrap it into parenthesis since it cant start with curly braces
console.log(a, b);
//23, 7
We should always wrap objects in parenthesis when declaring them to avoid error
openingHours: {
thu: {
open: 12,
close: 22,
},
fri: {
open: 11,
close: 23,
},
sat: {
open: 0, // Open 24 hours
close: 24,
},
}
since there's an object within an object, we use two curlies to depict this in code
const {
fri: { open: o, close: c },
} = openingHours;
console.log(o, c);
//11,23
full recap of what we learned so far
const restaurant = {
name: 'Classico Italiano',
location: 'Via Angelo Tavanti 23, Firenze, Italy',
categories: ['Italian', 'Pizzeria', 'Vegetarian', 'Organic'],
starterMenu: ['Focaccia', 'Bruschetta', 'Garlic Bread', 'Caprese Salad'],
mainMenu: ['Pizza', 'Pasta', 'Risotto'],
order: function (starterIndex, mainIndex) {
return [this.starterMenu[starterIndex], this.mainMenu[mainIndex]];
},
orderDelivery: function ({ starterIndex, mainIndex, time, address }) {
console.log(
` order received ${this.starterMenu[starterIndex]} and ${this.mainMenu[mainIndex]}, will be delivered to ${address} at ${time}`
);
},
};
restaurant.orderDelivery({
time: '22:30',
address: 'Via del Sole, 21',
mainIndex: 2,
starterIndex: 2,
});
// order received Garlic Bread and Risotto, will be delivered to Via del Sole, 21 at 22:30
The Spread Operator (...)
We can use the spread operator to unpack an array.
const arr = [7, 8, 9]; //array literal
const newArr = [1, 2, ...arr];
console.log(...newArr); //1 2 7 8 9
we can use spread operator to create a copy of an array and add to it
example 1:
const mainMenuCopy = [...restaurant.mainMenu];
// [['Pizza', 'Pasta', 'Risotto']
example 2:
const newMenu = [...restaurant.mainMenu, 'gnocci'];
console.log(newMenu);// ['Pizza', 'Pasta', 'Risotto', 'gnocci']
example 3:
const menu = [...restaurant.mainMenu, ...restaurant.starterMenu];
console.log(menu); // ['Pizza', 'Pasta', 'Risotto', 'Focaccia', 'Bruschetta', 'Garlic Bread', 'Caprese Salad']
using spread operator in a function
orderPasta: function (ing1, ing2, ing3) {
console.log(
`here is your delicious pasta with ${ing1}, ${ing2} and ${ing3}`
);
const ingredients = [
prompt(`let's make pasta! ingredient 1?`),
prompt(`ingredient 2?`),
prompt(` ingredient 3?`),
];
console.log(ingredients); // ['cheese', 'pesto', 'tomato']
restaurant.orderPasta(...ingredients);
//here is your delicious pasta with cheese, pesto and tomato
spread operator works on all iterables: things like arrays, strings, maps and sets, not objects!!)
spread operator used on string:
const str = 'Roxy';
const letters = [...str, '', 's'];
console.log(letters);
//['R', 'o', 'x', 'y', '', 's']
after 2016, we can also use spread operator for objects
const newRestaurant = { foundedIn: 1988, ...restaurant, founder: `Antonio` };
console.log(newRestaurant);
//{foundedIn: 1988, name: 'Classico Italiano', location: 'Via Angelo Tavanti 23, Firenze, Italy', categories: Array(4), starterMenu: Array(4), …}
categories
:
(4) ['Italian', 'Pizzeria', 'Vegetarian', 'Organic']
foundedIn
:
1988
founder
:
"Antonio"
location
:
"Via Angelo Tavanti 23, Firenze, Italy"
mainMenu
:
(3) ['Pizza', 'Pasta', 'Risotto']
name
:
"Classico Italiano"
openingHours
:
{thu: {…}, fri: {…}, sat: {…}}
order
:
ƒ (starterIndex, mainIndex)
orderDelivery
:
ƒ ({ starterIndex, mainIndex, time, address })
orderPasta
:
ƒ (ing1, ing2, ing3)
starterMenu
:
(4) ['Focaccia', 'Bruschetta', 'Garlic Bread', 'Caprese Salad']
Rest Pattern and Parameters
is the opposite of a spread operator where it collects items and pack them into an array
spread is on the right side of the assignment operator HOWEVER we can also use it on the left side!!
spread:
const arr = [1, 2, ...[3.4]];
rest:
const [a, b, ...others] = [1, 2, 3, 4, 5];
console.log(a, b, others);
//1 2 (3) [3, 4, 5]
it collects the element unused and puts them into others
example 2:
const [pizza, , risotto, ...otherFood] = [
...restaurant.mainMenu,
...restaurant.starterMenu,
];
console.log(pizza, risotto, otherFood);
// Pizza Risotto (4) ['Focaccia', 'Bruschetta', 'Garlic Bread', 'Caprese Salad'] it skips pasta as it is not included
the rest element must be the last element and there can be only one!!!
example 3: using rest patterns for objects
const { sat, ...weekDays } = restaurant.openingHours;
console.log(weekDays);
//{thu: {…}, fri: {…}}
example 4: using functions (REST ARGUMENT)
const add = function (...numbers = this is called a rest argument) {
let sum = 0;
for (let i = 0; i < numbers.length; i++) {
sum += numbers[i];
console.log(sum);
}
};
add(2, 3);
add(5, 3, 7, 2);
add(8, 2, 3, 2, 1, 4);
const x = [23, 5, 7];
add(...x);
short circuiting (&& and ||)
- logical operators can use any data type
- they can return any data type
- they do short circuiting / short circuit evaluation: if the first value is a truthy value, it will immediately return the truthy value but will return the last value if all of them are falsies
example 1:
console.log(3 || 'roxy');
// 3
since it immediately returns the truthy value, it will not even consider nor read the other option
example 2:
console.log('' || 'roxy'); //roxy
console.log(true || 0); //true
console.log(undefined || null); //null. even though null is a falsy
example 3:
console.log(undefined || 0 || '' || 'hello' || 23 || null);
//hello because its the first truthy value
|| short circuiting
instead of using a ternary operator for something like this
const guest1 = restaurant.numGuests ? restaurant.numGuests : 10;
console.log(guest1);
//10
= if numGuest exists show numGuest, if not show the default value of 10
we can also do this using short circuits for if, else statements
const guest2 = restaurant.numGuests || 10;
console.log(guest2);
//10
but both of these will not work if restaurant.numGuest will be 0 as 0 is a falsy value so it will go to the truthy value which is the default 10
&& short circuiting
works the exact oposite of the or value (||)
so it will focus on the first falsy value or the last value if all of them are truthy and will not focus on the next/ truthy value
example 1:
console.log(0 && 'Jonas'); //0
console.log(7 && 'Jonas'); //Jonas
console.log('hello' && 23 && null && 'jonas'); //null
using the && short circuit in place of an if statement
instead of
if (restaurant.orderPizza) {
restaurant.orderPizza('mushroom', 'cheese');
}
we can use
restaurant.orderPizza && restaurant.orderPizza('mushroom', 'cheese');
but this doesn't mean we need to replace all if, else statements with these!!! just use accordingly depending on the situation!!
The Nullish Coalescing Operator(??)
similar to the And or Or operator ( && , ||), the nullish operator works with the concept of nullish values instead of falsy values.
Nullish values are null and undefined ( so it can handle 0 or ' ')
therefore
restaurant.numGuests = 0;
const guestCorrect = restaurant.numGuests ?? 10;
console.log(guestCorrect); //0
the 0 will show up instead of going to the default value of 10 as the nullish operator recognizes 0 as a value.
Recap and simplifying operators (||, &&, ??)
rest1.numGuests = rest1.numGuests || 10;
rest2.numGuests = rest2.numGuests || 10;
rest1.numGuests ||= 10;
rest2.numGuests ||= 10; //kinda like +=
rest2.owner = rest2.owner && 'anonymous';
// since the first value is truth it pushes out the 'falsy value'
rest2.owner = rest2.owner && 'anonymous';
rest1.owner &&= 'anonymous';
rest2.owner &&= 'anonymous';
console.log(rest1.owner);
console.log(rest2.owner);
rest1.numGuests ??= 10;
rest2.numGuests ??= 10;
For Of Loop
instead of setting different parameters like the for loop we can simply assign a vairable we want to use directly
const menu = [...restaurant.mainMenu, ...restaurant.starterMenu];
for (const item of menu) console.log(item);
//Pizza
Pasta
Risotto
Focaccia
Bruschetta
Garlic Bread
Caprese Salad
there is also something called entries which we will learn later but to simply put it, its to create a numbered list
for (const item of menu.entries()) {
console.log(`${item[0] + 1}: ${item[1]}`);
}
//1: Pizza
2: Pasta
3: Risotto
4: Focaccia
5: Bruschetta
6: Garlic Bread
7: Caprese Salad
however we can simplify this further by destructuring the above
for (const [i, el] of menu.entries()) {
console.log(`${i + 1}: ${el}`);
}
further excercises
//the for of loop
//8.1
let pageSum = 0;
for (let book of books) {
pageSum += book.pages;
console.log(pageSum);
}
//8.2
let allAuthors = [];
for (const book of books) {
if (typeof book.author === `string`) {
allAuthors.push(book.author);
} else {
for (const author of book.author) {
allAuthors.push(author);
}
}
}
console.log(allAuthors);
//8.3
for (const [i, name] of allAuthors.entries()) {
console.log(` ${i + 1}: ${name} `);
}
Enhanced object literals
thanks to ES6 updates we can simplify some of the code we write through using enhance object literals: writing literally using obj literal syntax
- if we have a seperate object and we want to insert it into another we can just write the name into the object
example:
const hours = {
[weekDays[3]]: {
open: 12,
close: 22,
},
[weekDays[4]]: {
open: 11,
close: 23,
},
[weekDays[2 + 3]]: {
open: 0, // Open 24 hours
close: 24,
},
};
const restaurant = {
name: 'Classico Italiano',
location: 'Via Angelo Tavanti 23, Firenze, Italy',
categories: ['Italian', 'Pizzeria', 'Vegetarian', 'Organic'],
starterMenu: ['Focaccia', 'Bruschetta', 'Garlic Bread', 'Caprese Salad'],
mainMenu: ['Pizza', 'Pasta', 'Risotto'],
hours, // like this!!
}
- we can also simplify functions in an object
instead of writing a key: name of function and value: function, we can directly create a function like this
order(starterIndex, mainIndex) {
return [this.starterMenu[starterIndex], this.mainMenu[mainIndex]];
},
- we can also reference other arrays into an object
example:
const weekDays = ['mon', 'tues', 'wed', 'thurs', 'fri', 'sat', 'sun'];
const hours = {
[weekDays[3]]: {
open: 12,
close: 22,
},
[weekDays[4]]: {
open: 11,
close: 23,
},
[weekDays[2 + 3]]: {
open: 0, // Open 24 hours
close: 24,
},
};
Optional Chaining (?.)
we can use optional chaining to see if a certain variable exists!
- optional chaining in an object
console.log(restaurant.hours?.mon?.open);
the ?. works as a chain gate, it will only move onto the next element if the variable exists. if not it will show up as undefined or as the default value set
const days = ['mon', 'tues', 'wed', 'thurs', 'fri', 'sat', 'sun'];
for (const day of days) {
console.log(day);
const open = restaurant.hours[day]?.open ?? 'closed';
console.log(`on ${day}, we open at ${open}`);
}
- optional chaining in methods
console.log(restaurant.order?.(0, 1) ?? 'method does not exist');
console.log(restaurant.orderRistto?.(0, 1) ?? 'method does not exist');
- optional chaining in arrays
//arrays
const users = [{ name: 'jonas' }, { email: `hello@jonas.io` }];
console.log(users[0]?.name ?? `user array empty`);
optional chaining and the nullish operator was made to use side by side like the case above
Looping Objects: Object Keys, Values, and Entries
As we have learned before in objects there are keys and values. And we can use these to retrieve information.
const hours = {
[weekDays[3]]: {
open: 12,
close: 22,
},
[weekDays[4]]: {
open: 11,
close: 23,
},
[weekDays[5]]: {
open: 0, // Open 24 hours
close: 24,
},
};
const properties = Object.keys(hours);
console.log(properties);
let openStr = `we are open for ${properties.length} days`;
for (const day of Object.keys(hours)) {
openStr += `${day},`;
}
console.log(openStr);
// we are open for 3 days fri,sat, sun
const values = Object.values(hours);
console.log(values);
//0: {open: 12, close: 22}
1: {open: 11, close: 23}
2: {open: 0, close: 24}
const entries = Object.entries(hours);
// console.log(entries);
//
combined togther:
for (const [key, { open, close }] of entries) {
console.log(`on ${key} we open at ${open} and close at ${close}`);
}
on thurs we open at 12 and close at 22
script.js:78 on fri we open at 11 and close at 23
script.js:78 on sat we open at 0 and close at 24