Day 11. Destructuring and Spreading_Exercise


Level 1 / Level 2 / Level 3

👟Level 1.

1) Destructure and assign the elements of constants array to e, pi, gravity, humanBodyTemp, waterBoilingTemp.
const constants = [2.72, 3.14, 9.81, 37, 100];
let [e, pi, gravity, humanBodyTemp, waterBoilingTemp] = constants

console.log(pi);  // 3.14
console.log(humanBodyTemp);  // 37


2) Destructure and assign the elements of countries array to fin, est, sw, den, nor.
const countries = ['Finland', 'Estonia', 'Sweden', 'Denmark', 'Norway']
let [fin, est, sw, den, nor] = countries;

console.log(est);  // Estonia
console.log(nor);  // Norway


3) Destructure the rectangle object by its properties or keys.
const rectangle = {
  width: 20,
  height: 10,
  area: 200,
  perimeter: 60
}
let {width, height, area, perimeter} = rectangle;

console.log(width);  // 20
console.log(area);  // 200


👟Level 2.

const users = [
{
  name:'Brook',
  scores:75,
  skills:['HTML', 'CSS', 'JS'],
  age:16
},
{
  name:'Alex',
  scores:80,
  skills:['HTML', 'CSS', 'JS'],
  age:18
},
{
  name:'David',
  scores:75,
  skills:['HTML', 'CSS'],
  age:22
},
{
  name:'John',
  scores:85,
  skills:['HTML'],
  age:25
},
{
  name:'Sara',
  scores:95,
  skills:['HTML', 'CSS', 'JS'],
  age: 26
},
{
  name:'Martha',
  scores:80,
  skills:['HTML', 'CSS', 'JS'],
  age:18
},
{
  name:'Thomas',
  scores:90,
  skills:['HTML', 'CSS', 'JS'],
  age:20
}
]


1) Iterate through the users array and get all the keys of the object using destructuring.
// get the keys with destructuring
for (const {name, scores, skills, age} of users) {
  console.log(Object.keys({name, scores, skills, age}));
}
/*
  ['name', 'scores', 'skills', 'age']
  ['name', 'scores', 'skills', 'age']
  ['name', 'scores', 'skills', 'age']
  ['name', 'scores', 'skills', 'age']
  ['name', 'scores', 'skills', 'age']
  ['name', 'scores', 'skills', 'age']
*/


// get the keys without destructuring
for (const element of users) {
  console.log(Object.keys(element));
}


// + get the values with destructuring
for (const {name, scores, skills, age} of users) {
  console.log(Object.values({name, scores, skills, age}));
}
/*
  ['Brook', 75, ['HTML', 'CSS', 'JS'], 16]
  ['Alex', 80, ['HTML', 'CSS', 'JS'], 18]
  ['David', 75, ['HTML', 'CSS'], 22]
  ['John', 85, ['HTML'], 25]
  ['Sara', 95, ['HTML', 'CSS', 'JS'], 26]
  ['Martha', 80, ['HTML', 'CSS', 'JS'], 18]
  ['Thomas', 90, ['HTML', 'CSS', 'JS'], 20]
*/


2) Find the people who have less than two skills.
for (const {name, scores, skills, age} of users) {
  if (skills.length < 2) {
    console.log(name);
  }
}
// John


👟Level 3.

1) Destructure the countries object, then print name, capital, population and languages of all countries.
for (const {name, capital, languages, population, ...rest} of countries_data) {
  console.log(name, capital, population, languages);
}

/*
  Afghanistan Kabul 40218234 (3) ['Pashto', 'Uzbek', 'Turkmen']
  Åland Islands Mariehamn 28875 ['Swedish']
  ...
  Zimbabwe Harare 14862927 (3) ['English', 'Shona', 'Northern Ndebele']
*/

I used spread syntax(...) because I didn’t need other elements(flag, region, area…) for printing.

2) A junior developer structure student name, skills and score in array of arrays which may not easy to read. Destructure the following array name to name, skills array to skills, scores array to scores, JavaScript score to jsScore and React score to reactScore variable in one line.
const student = ['David', ['HTML', 'CSS', 'JS', 'React'], [98, 85, 90, 95]];
let [name, skills, [, , jsScore, reactScore]] = student;
console.log(name, skills, jsScore, reactScore);

// David (4) ['HTML', 'CSS', 'JS', 'React'] 90 95


3) Write a function called convertArrayToObject which can convert the array to a structure object.
  • Expected output:
const students = [
  ['David', ['HTML', 'CSS', 'JS', 'React'], [98, 85, 90, 95]],
  ['John', ['HTML', 'CSS', 'JS', 'React'], [85, 80, 85, 80]]
]

console.log(convertArrayToObject(students))
/*
  [
    {
      name: 'David',
      skills: ['HTML','CSS','JS','React'],
      scores: [98,85,90,95]
    },
    {
      name: 'John',
      skills: ['HTML','CSS','JS','React'],
      scores: [85, 80,85,80]
    }
  ]
*/


const students = [
  ['David', ['HTML', 'CSS', 'JS', 'React'], [98, 85, 90, 95]],
  ['John', ['HTML', 'CSS', 'JS', 'React'], [85, 80, 85, 80]]
]

const convertArrayToObject = (arr) => {
  const newArray = [];
  for (const [name, skills, scores] of arr) {
    newArray.push({name: name, skills: skills, scores: scores});
  }
  return newArray;
}

console.log(convertArrayToObject(students));
/*
  [
    {
    name: 'David',
    skills: ['HTML', 'CSS', 'JS', 'React'], 
    scores: [98, 85, 90, 95]
    },
    {name: 'John', 
    skills: ['HTML', 'CSS', 'JS', 'React'], 
    scores: [85, 80, 85, 80]
    }
  ]
*/


  • Mistakes I’ve been through
const convertArrayToObject = (arr) => {
  for (const element of arr) {
    let [name, skills, scores] = element;
    return {name: name, skills: skills, scores: scores};
  }
}
console.log(convertArrayToObject(students));
/* {
  name: 'David',
  skills: ['HTML', 'CSS', 'JS', 'React'], 
  scores: [98, 85, 90, 95]
} */

When I first made a function, I wrote the code like below. It would just print out the first element. It must have been like that, because return terminates the function right away. I overlooked it. The for loop wouldn’t have worked at all.

const convertArrayToObject = (arr) => {
  for (const [name, skills, scores] of arr) {
    console.log({name: name, skills: skills, scores: scores});
  }
}
console.log(convertArrayToObject(students));
/*
  {name: 'David', skills: ['HTML', 'CSS', 'JS', 'React'], scores: [98, 85, 90, 95]}
  {name: 'John', skills: ['HTML', 'CSS', 'JS', 'React'], scores: [85, 80, 85, 80]}
*/

When I changed return to console.log it would print out both objects of students. Destructuring inside the for loop is possible, but I can also destructure the element inside the parentheses of for loop. Then to print both objects in one array, I made a new array and pushed the objects in each iteration.

4) Copy the student object to newStudent without mutating the original object. In the new object add the following.
  • Add Bootstrap with level 8 to the front end skill sets
  • Add Express with level 9 to the back end skill sets
  • Add SQL with level 8 to the data base skill sets
  • Add SQL without level to the data science skill sets
  const student = {
    name: 'David',
    age: 25,
    skills: {
      frontEnd: [
        { skill: 'HTML', level: 10 },
        { skill: 'CSS', level: 8 },
        { skill: 'JS', level: 8 },
        { skill: 'React', level: 9 }
      ],
      backEnd: [
        { skill: 'Node',level: 7 },
        { skill: 'GraphQL', level: 8 },
      ],
      dataBase:[
        { skill: 'MongoDB', level: 7.5 },
      ],
      dataScience:['Python', 'R', 'D3.js']
    }
  }


  • Expected output
    {
      name: 'David',
      age: 25,
      skills: {
        frontEnd: [
          {skill: 'HTML',level: 10},
          {skill: 'CSS',level: 8},
          {skill: 'JS',level: 8},
          {skill: 'React',level: 9},
          {skill: 'BootStrap',level: 8}
        ],
        backEnd: [
          {skill: 'Node',level: 7},
          {skill: 'GraphQL',level: 8},
          {skill: 'Express',level: 9}
        ],
        dataBase: [
          { skill: 'MongoDB',level: 7.5},
          { skill: 'SQL',level: 8}
        ],
        dataScience: ['Python','R','D3.js','SQL']
      }
    }
    


const {name, age, skills} = student;
const newStudent = {name, age, skills};
let {frontEnd, backEnd, dataBase, dataScience} = skills;
frontEnd.push({skill: 'Bootstrap', level: 8});
backEnd.push({skill: 'Express', level: 9});
dataBase.push({skill: 'SQL', level: 8});
dataScience.push('SQL');

The push() part went well, but I found out that the original object student has also been changed. The quiz asked me not to mutate the original object, so I have to fix the code.

const newStudent = {...student};
let {name: n, age: a, skills: s} = newStudent;
let {frontEnd, backEnd, dataBase, dataScience} = s;
frontEnd.push({skill: 'Bootstrap', level: 8});
backEnd.push({skill: 'Express', level: 9});
dataBase.push({skill: 'SQL', level: 8});
dataScience.push('SQL');

I tried to rename the properties to only change values of the new array, but it didn’t work. Even though I renamed the variables, they were still pointing to the same thing.


+ Further Study: Shallow copy/Deep copy

The problem was that I didn’t ‘deep copied’ the original array. I did a ‘shallow copy’, which the references, not values, are copied. The reference variables in the original array and the copied array all point to the same value, so when I change the value of an element at the copied array, the original value would change, too. The articles I’ve read all recommended something called JSON, but I didn’t know it.

I tried using Object.assign(). This method copies an object without modifying the original object.

const newStudent = Object.assign({}, student);

const {name, age, skills} = newStudent;
let {frontEnd, backEnd, dataBase, dataScience} = skills;
frontEnd.push({skill: 'Bootstrap', level: 8});
backEnd.push({skill: 'Express', level: 9});
dataBase.push({skill: 'SQL', level: 8});
dataScience.push('SQL');

It didn’t work as well. I thought it would work because I destructured the object after I copied it. But it somehow didn’t work.

So I tried to use different variable names like below:

const newStudent = Object.assign({}, student);
let {n, a, s} = newStudent;
let {frontEnd, backEnd, dataBase, dataScience} = s;
frontEnd.push({skill: 'Bootstrap', level: 8});
backEnd.push({skill: 'Express', level: 9});
dataBase.push({skill: 'SQL', level: 8});
dataScience.push('SQL');

It didn’t work, too.

When destructuring an object, the variable I use should be the same as the key or property of the object.

const newStudent = {...student}
const {name, age, skills} = newStudent;
let {frontEnd, backEnd, dataBase, dataScience} = skills;
frontEnd.push(skills, {skill: 'Bootstrap', level: 8});
backEnd.push({skill: 'Express', level: 9});
dataBase.push({skill: 'SQL', level: 8});
dataScience.push('SQL');

  • Mistakes I’ve been through

At the very first, I wanted to assign variables all at once, so I wrote:

const {name, age, skills.frontEnd, skills.backEnd, skills.dataBase, skills.dataScience} = student;

It didn’t work, and gave me an error message that tells “Unexpected token ‘,’”. The bracket notation didn’t work as well. I searched stackoverflow to find a way to destructure a nested object properties inside an array in multiple levels. I’ve read it but the case was only for arrays that only have objects.

In this quiz, the ‘student’ object has three properties(name, age, skills) and one of the property(skills) has a value of objects(frontEnd, backEnd, dataBase, dataScience). So I decided to first destructure those three properties and then destructure the ‘skills’ property once more.

Another mistake I had was about destructuring.

let skills = {frontEnd, backEnd, dataBase, dataScience};

I meant to destruct the skills array, but it had a syntax error. It was because it wasn’t a destructing, but rather another declaration of skills. For destructing I have to switch the position.

Leave a comment