My first question is; why is destructuring used here as opposed to const a=0, b=0, c=0, d=0, f=0;
? This seems far less verbose when compared to the original technique?
If you declare the variables as you suggest, you will not get the previous values from the object:
function original(obj) {
const { a=0, b=0, c=0, d=0, f=0 } = obj;
console.log(`const { a=0, b=0, c=0, d=0, f=0 } = obj;
a = ${a}
b = ${b}
c = ${c}
d = ${d}
f = ${f}
`);
}
function proposed(obj) {
const a=0, b=0, c=0, d=0, f=0;
console.log(`const a=0, b=0, c=0, d=0, f=0;
a = ${a}
b = ${b}
c = ${c}
d = ${d}
f = ${f}
`);
}
const obj = { a: 1, b: 2, d: 4};
original(obj);
proposed(obj);
Destructuring will take the property a
from the object on the right side of the =
and will assign zero only if it doesn't find it. So, it's similar to directly getting the properties:
function explicit(obj) {
const a = obj.a,
b = obj.b,
c = obj.c,
d = obj.d,
f = obj.f;
console.log(`const a = obj.a, b = obj.b, c = obj.c, d = obj.d, f = obj.f;
b = ${b}
c = ${c}
d = ${d}
f = ${f}
`);
}
const obj = { a: 1, b: 2, d: 4};
explicit(obj);
This doesn't have a fallback to zero just for clarity as to what is happening. A fallback value can be done with the conditional operator ? :
which will look like this:
const obj = {b: 2};
const a = obj.a ? obj.a : 0;
const b = obj.b ? obj.b : 0;
console.log(`Using the conditional operator "? :"
a = ${a}
b = ${b}
`)
Alternatively, there is an idiomatic usage of the OR operator ||
that can also produce a fallback value:
const obj = {b: 2};
const a = obj.a || 0;
const b = obj.b || 0;
console.log(`Using the OR operator "||"
a = ${a}
b = ${b}
`)
These aren't completely the same as providing a default value in destructuring but at least close enough for illustration of the alternative. Difference is in how falsy values are handled but we can ignore that for now.
So, with this in mind, destructuring is far less verbose than the normal way:
const a = obj.a || 0,
b = obj.b || 0,
c = obj.c || 0,
d = obj.d || 0,
f = obj.f || 0;
//compared with
const { a=0, b=0, c=0, d=0, f=0 } = obj;
Secondly, why is it that the reduce method returns one object containing all the grades with their corresponding quantities as opposed to a separate object for each grade?
Well, this is how Array#reduce
works. I'm going to simplify things a bit and skip over irrelevant details for brevity - feel free to read through the MDN documentation as it's vastly more thorough than I will be here.
The form of reduce
is:
<array>.reduce(callback, initialValue)
Where youu supply it with a callback function that will be called once for each item in the array with two parameters:
function callback(previousResult, currentItem){}
- The previous result of callback function. Unless this is the first time it's called in which case it will use
initialValue
supplied to .reduce
.
- note -
previousResult
is very frequently named prev
for "previous" or acc
for "accumulator". I chose the long form for clarity but as you can see the one in your code is acc
- it is an idiomatic name for this parameter.
- The current item being operated on. Items will be visited one by one in sequence.
Quick illustration using a simple reduce
to sum all items in the array:
callback = (acc, currentNumber) => acc + currentNumber;
initialValue = 0;
[1, 2, 3].reduce(callback, initialValue);
then the steps .reduce
would are illustrated here:
[3, 5, 7]
^ ^ ^
---------------------- | |
acc = 0 | | |
currentNumber = 3 | | |
result = 3 | | |
------------------- | |
| |
--------------------------- |
acc = 3 | |
currentNumber = 5 | |
result = 8 | |
------------------- |
|
--------------------------------
acc = 8 |
currentNumber = 7 |
result = 15|
-------------------
The same applies with the code in the question - each time only a single object is produced by the callback, so next time it's called acc
would get a single object again.
Finally, the way the object is updated by using the object spread notation ...
to clone and modify a value. {...acc}
will create a new object that has the same values as the previous one and {...acc, a: a + 1}
will clone it and change the property a
to the value of the variable a
plus 1. If there was no a
property before, then it will be added and since the variable a
would be zero, then you'd get { a: 1 }
.
const initial = { a: 5};
const obj1 = {...initial, a: 6};
console.log("obj1", obj1);
const obj2 = {...obj1, b: 1};
console.log("obj2", obj2);
const obj3 = {...obj2, b: 2};
console.log("obj3", obj3);