Rest Pattern and Rest Parameters
The rest pattern looks the same as the spread operator (...) but it does the opposite. The spread operator builds new arrays or passes multiple values to an existing function, expanding an array into individual elements. The rest pattern uses the same syntax but in order to collect multiple elements and condense them into an array (the spread unpacks an array into elements; the rest packs an array from elements.)
const arr = [1, 2, ...[3, 4]];
Above we are using the spread syntax. We know that because we are using it on the right hand side of the assignment operator (the equal sign).
const [a, b, ...others] = [1, 2, 3, 4, 5];
Above we are using the rest syntax because the "..." is on the left side of the variable definition.
console.log(a, b, others);
Output: 1 2 [ 3, 4, 5 ]
The first and second elements become the first and second variables (a and b), then the "others" variable is when the rest pattern comes into play, it takes the remaining elements of the array and put them into a new array. The rest pattern collects the unused elements in the destructuring assignment.
There can only be one rest pattern in any given destructuring assignment.
Rest Pattern in objects
It works the same as in arrays, but the remaining elements will be collected into a new object.
const restaurant = {
name: "Ristorante di Paolo",
location: "Chipilo, Mexico",
categories: ["Italian", "Pizzeria", "Vegetarian"],
starterMenu: ["Salad", "Garlic Bread", "Cheese"],
mainMenu: ["Pizza", "Pasta", "Lasagna"],
openingHours: {
thu: {
open: 12,
close: 22,
},
fri: {
open: 11,
close: 23,
},
sat: {
open: 0, // Open 24 hours
close: 24,
},
},
order: function (starterIndex, mainIndex) {
return [this.starterMenu[starterIndex], this.mainMenu[mainIndex]];
},
};
const { sat, ...weekdays } = restaurant.openingHours;
console.log(weekdays);
Output: { thu: { open: 12, close: 22 }, fri: { open: 11, close: 23 } }
Rest Pattern in Functions
const add = function (...numbers) { //1
// 2
let sum = 0;
for (let i = 0; i < numbers.length; i++) sum += numbers[i];
console.log(sum);
};
add(2, 3); // 5
add(1, 2, 3, 4, 5); // 15
1.In here we unpack the values
2.Any arbitrary amount of arguments should work for this function.
We can also do this with arrays
const x = [14, 15, 48];
add(...x);
Output: 77 - In here we pack the values again
This way the function accepts an array, and single values, no matter what we feed the function, it will work.
Short Circuiting (&& and ||)
We can also use non boolean values to get the most out of the AND and OR operators, we just need to know how and when.
There are three "advanced" properties about logical operators: They can use any data type, they can return any data type, and they can short-circuit, which means that if the first operand is a truthy value, it will return that value, and JS will not even look at the second operand.
console.log(5 || "Eric"); // 5
console.log("" || "Eric"); // Eric
console.log(true || 0); // true
console.log(undefined || null || undefined); // null - 1
1.Even though "null" is a falsy value, the rule says that the result will be the last operand.
In a strain of OR operands, we will get as result the first truthy value (Because it is short circuiting the OR operation)
For the AND operator, the logic is similar, but the AND operator works in the exact opposite way. The best way is to learn with examples:
The AND operator short circuits when the first value is a falsy and returns the first value, without even looking at the second operand, because if the first operand is false, then the whole evaluation will be false, there's no need to evaluate the whole thing.
If the first operand is truthy, the evaluation continues, and then will return the second operand.
If any of the operands is false, the evaluation stops at that operand and will return the falsy value, because the whole evaluation will be false anyway.
console.log(0 && "Eric"); // 0
console.log(7 && "Eric"); // Eric
console.log("Hello" && 23 && null && "Eric"); // null
Nullish Coalescing operator
When we use the OR operator, we can set a default value in case we get a falsy value for our variable, justl ike this:
restaurant.numGuests = 0; // 1
const guests2 = restaurant.numGuests || 10;
console.log(guests2); // 2
1.If we don't define the number of guests, we'll get the default value of 10, which is good, but since we defined it, this code is bugged.
2.We will print "10" because since we set the number of guests to 0, the value is a falsy and then we'll get the 10 as default.
But this is actually wrong, because since we established that the number of guests is zero, we don't want to return 10 guests... we have a solution introduced in ES20:
Nullish values are "null" and "undefined". Works as if zero and empty string were not falsy values.
const guests = restaurant.numGuests ?? 10;
console.log(guests); // 0
Looping arrays: The For-of Loop
In the For-of loop you don't really need a counter, a condition and update the counter, it is much more simpler.
const menu = ["Salad", "Garlic Bread", "Cheese", "Pizza", "Pasta", "Lasagna"];
for (const item of menu) // 1
console.log(item);
1.We create a variable X and then we can log said variable.
The For of Loop loops through the entire array and in each iteration gives us access to each element of the array. This allows us to use the "continue" and "break" keywords.
Let's say we want the index and the element from an array.
for (const item of menu.entries()) { //1
console.log(item);
}
1.We use the .entries method which allows us to return the item and the index where they are.
Output: So if we wanted to display a numbered menu, we would do something along the lines below: Output But this is an outdated way, there's a cleaner way to do this by destructuring We already have an array called item, so we can destructure that one and create two variables This is an object literal because we used the curly braces syntax, and we literally wrote the code for it inside them. ES6 introduced 3 enhancements of writing objects: The object Eric outside of the hiveUsers object. Before ES6 if we wanted the Eric object to be inside the hiveUsers objects, we would have to write: We usually write object properties with function elements like this: But with ES6, we can just write functions like below: This second enhancement is cleaner, and both work the same. We can actually use both, I personally prefer the first one but it depends on taste, for me since I'm a rookie the first one is more explicit and more understandable. We can now compute property names instead of having to write them manually (compute means calculate). Let's say that we wan't to take the property names of the hiveUsers object, out of the someUsers array. Objects are not iterables but we can actually loop over them using an indirect way. We have different options depending on what we want to loop over (the property names (keys), the property values or both). We will not be looping over the object itself, but over an array that we create out of the object. Output: What we did is store the keys of the object by creating an array of such keys, and then we just looped through it while calling the variable. For the values is the same logic: But let's say we want to loop over the whole object and return keys and values Output:
[[ 'Roeland', { username: '@roelandp', hivepower: 250000 }],'Gandalf', { username: '@gtg', hivepower: 750000 }]] That's enough for today, tonight I will post the third and last post about Data Structures and we'll stop diving into them, I think it's more than enough to have our hands full for days, wo why push it? I hope this post was helpful in your path to become a JavaScript developer, if it wasn't, I'm always open to feedback.
[ 0, 'Salad' ]
[ 1, 'Garlic Bread' ]
[ 2, 'Cheese' ]
[ 3, 'Pizza' ]
[ 4, 'Pasta' ]
[ 5, 'Lasagna' ]
for (const item of menu.entries()) {
console.log(`${item[0] + 1}:${item[1]}`);
}
1:Salad
2:Garlic Bread
3:Cheese
4:Pizza
5:Pasta
6:Lasagnafor (const [i, element] of menu.entries()) {
console.log(`${i + 1}: ${element}`);
}
Enhanced Object Literals
const restaurant = {}; // 1
const Eric = {
userName: '@anomadsoul',
hivePower: 5.0,
};
First enhancement
const hiveUsers = {
Eric = Eric, // The annoying part is that the property name is exactly the same as the variable name as the one from which we are getting the new object, but with enhanced object literals, we don't need to do this, we can just:
Eric, // This works the same way as the above, but in a cleaner way.
Roeland: {
username: '@roelandp',
hivepower: 250.000,
},
Gandalf: {
username: '@gtg',
hivepower: 750.000,
}
};
Second enhancement
order: function (starterIndex, mainIndex) {
return [this.starterMenu[starterIndex], this.mainMenu[mainIndex]];
}
order(starterIndex, mainIndex) {
return [this.starterMenu[starterIndex], this.mainMenu[mainIndex]];
}
Third enhancement
const someUsers = ['haejin', 'roeland', 'tarazkp', 'gtg']
const hiveUsers = {
[someUsers[1]]: { // we don't want to write them manually. We can put any expression inside the square brackets.
username: '@roelandp',
hivepower: 250.000,
},
Gandalf: {
username: '@gtg',
hivepower: 750.000,
}
};
Looping through Objects
const hiveUsers = {
Roeland: {
username: "@roelandp",
hivepower: 250000,
},
Gandalf: {
username: "@gtg",
hivepower: 750000,
},
};
/*
for (const user of Object.keys(hiveUsers)) {
console.log(user);
}
Roeland;
Gandalf;const values = Object.values(hiveUsers);
console.log(values);
//Output
[{ username: '@roelandp', hivepower: 250 },{ username: '@gtg', hivepower: 750 }]
const entries = Object.entries(hiveUsers);
console.log(entries);