Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript JavaScript Loops, Arrays and Objects Tracking Data Using Objects The Build an Object Challenge, Part 2 Solution

David Luhr
David Luhr
4,053 Points

Is it okay to use a "for in" loop inside of the "for" loop to print out each of the key/value pairs?

I was surprised that the solution for this challenge included manually accessing each property of the student object and appending the key/value pair to the message string.

Because we learned "for in" loops earlier in this course, I tried the following and the resulting markup looked as expected:

for(var i = 0; i < students.length; i++) {
  student = students[i];
  message += '<h2>Student: ' + student.name + '</h2>';
  for(var key in student) {
    message += '<p>' + key + ': ' + student[key] + '</p>';
  }
}

Is this solution ok? Are there any downsides to using the "for in" loop inside of the "for" loop in this way? It seems like this is most scalable, as it would list out any properties, even as the data structure changes.

2 Answers

Steven Parker
Steven Parker
229,732 Points

The benefit is also the downside.

As you point out, looping through the properties will show any new ones that have been added. But it will not show any expected ones that are missing. In the original solution, a missing property would still be named and listed as "undefined", but in the modified strategy, it would simply not be shown. The data might also be occasionally contain private fields only intended for authorized viewers that would be exposed by the new method.

So each method would be best suited to different requirements. Do you want to list only certain fields and alert the viewer to missing data, or do you want to just list the entire database contents?

David Luhr
David Luhr
4,053 Points

Thank you for the explanation of the pros/cons of each approach. I definitely didn't consider the advantage of undefined properties being reported. Also, I immediately saw a limitation to the "for in" approach later in this course when the instructor refactors the building of the HTML message to an external function, in which I wouldn't have access to the keys in student(s). Thanks again for the help!

Hi David, As with almost everything in development, there are always multiple roads that will lead to the same result. In this particular example, it is certainly possible to (and in my opinion a better practice to) use automation in the way of iterating with loops and built-in JS methods.

A couple things if you'll allow me: in your code you are making a global variable of the student by not using a var, let, or const keyword. The keyword let is a great new ES6 feature the allows developers to use block scope variables, meaning their values will never leak out of the (block/function/for-loop) scope they were created in. As you continue on your journey learning JavaScript, you'll learn more eloquent ways to perform the same tasks, as you already have by keeping your code DRY in your example above!

Here's an example of code progression that I hope inspires you to learn more as I was learning to code only a year and half ago: THIS

let message = '';
function createDataSheet(studentData, output) {
  for(let i=0, l=studentData.length; i<l; i++) {
    message += '<h2>Student: ' + studentData[i].name +'</h2>';
    for(let key in studentData[i]) {
      message += '<p>' + [key] + ': ' + studentData[i][key] +'</p>';
    }
  }
}
createDataSheet(students, message)

console.log(message);

IS THE SAME AS THIS

let message = '';
function createDataSheet(studentData, output) {
  for(let i=0, l=studentData.length; i<l; i++) {
    message += `<h2>Student: ${studentData[i].name}</h2>`;
    for(let key in studentData[i]) {
      message += `<p>${key}: ${studentData[i][key]}</p>`;
    }
  }
}
createDataSheet(students, message)

console.log(message);

IS THE SAME AS THIS

const createDataSheet = (data, input) => {
  data.forEach((student) => {
    input += `<h2>Student: ${student.name}</h2>`;
    Object.keys(student).forEach(key => input += `<p>${key}: ${student[key]}</p>` );
  });
  return input;
};
console.log(createDataSheet(students, ''));

The difference in from the last version to the first is that in the last version I am using built-in methods. As you learn more and begin using built-in methods you'll find that using these methods over traditional for-loops and for-in loops will lower the chance of creating an unknown/unseen error.

Hope this helps and happy coding :) Rich

David Luhr
David Luhr
4,053 Points

Thank you for the thorough examples, Rich. I'm looking forward to learning ES6 more robustly, as the syntax, template strings, new variable declarations, and everything else makes for much more elegant code, as you've shown. I appreciate seeing the evolution of your approach.