In our starter files, open the index.html page from this lessons folder:
07.Objects-In-More-Depth > 07.Looping-with-objects
for...in
loopObjects can have many values as we know, and just like arrays, looping is a convenient way to repeat something for each property. There are multiple ways of looping over objects, and first we will look at the for...in
loop.
Inside this lessons file, we have a constructor function to create new users which we have seen before:
function User(first, last, occupation, lives) {
this.firstName = first;
this.lastName = last;
this.occupation = occupation;
this.lives = lives;
}
// User.prototype.cool = true;
// User.prototype.fullName = function () {
// return this.firstName + ' ' + this.lastName;
// };
const homer = new User(
"Homer",
"Simpson",
"Safety Inspector",
"Springfield"
);
The prototype additions are commented out and we will see why soon. A for...in
loop should look pretty familiar, we already looked at this in the looping section, but we will discover something else related to it.
As a refresher, this is how it looks:
// property name eg firstName / object to loop over
for (const property in homer) {
// property name / value
console.log(`${property}: ${homer[property]}`);
}
And the result in the console:
firstName: Homer
lastName: Simpson
occupation: Safety Inspector
lives: Springfield
We can then use this to construct elements to add to the DOM.
First, an unordered list which can be a wrapper for our values:
<body>
<!-- add ul -->
<ul></ul>
<script>
Then into the script
:
// ...
const homer = new User(
"Homer",
"Simpson",
"Safety Inspector",
"Springfield"
);
// 1. select new ul element:
const ul = document.querySelector("ul");
for (const property in homer) {
// 2. create list items and add to ul:
const li = document.createElement("li");
const text = document.createTextNode(`${property}: ${homer[property]}`);
li.appendChild(text);
ul.appendChild(li);
}
This will display in the browser as a list. This is useful to show our object in a structured way in the browser.
But, back to this prototype
which was commented out.
Uncomment out prototype section to make it active.
User.prototype.cool = true;
User.prototype.fullName = function () {
return this.firstName + ' ' + this.lastName;
};
We also now see prototype values in the browser. This is something we need to watch out for.
hasOwnProperty
If we don’t want to loop over these prototypes, we can eliminate them using an Object method called hasOwnProperty
, which we can use inside of the loop:
for (const property in homer) {
if (homer.hasOwnProperty(property)) {}
const li = document.createElement('li');
// ...
Here we access our homer
object, and then check each property one by one. We are checking if the properties belong to the homer
object, or if it is inherited via the prototype
. If this is true, we want to run our code, if not, it will be a prototype
value and therefore ignored.
We can now move the code in our loop to be inside the if
statement.
for (const property in homer) {
if (homer.hasOwnProperty(property)) {
const li = document.createElement('li');
const text = document.createTextNode(
`${property}: ${homer[property]}`
);
li.appendChild(text);
ul.appendChild(li);
}
}
This will now remove the prototype values from our list.
entries()
Other ways of looping over objects are to convert them to arrays. Object has some methods which we can use to do this. Depending on if we want to access the objects property, the value, or both as a pair.
Beginning with a method called entries()
:
console.log(Object.entries(homer));
Console result:
0: (2) ['firstName', 'Homer']
1: (2) ['lastName', 'Simpson']
2: (2) ['occupation', 'Safety Inspector']
3: (2) ['lives', 'Springfield']
length: 4
[[Prototype]]: Array(0)
This results in an array with four values. Each value also contains an array for each property in our object. This method does not include the prototype values like for...in
loops do, so we can use this is our loop without having to use the if
statement.
Duplicate the for...in
loop and comment out original.
// ...
const ul = document.querySelector('ul');
// for (const property in homer) {
// if (homer.hasOwnProperty(property)) {
// const li = document.createElement('li');
// const text = document.createTextNode(
// `${property}: ${homer[property]}`
// );
// li.appendChild(text);
// ul.appendChild(li);
// console.log(`${property}: ${homer[property]}`);
// }
// }
for (const property in homer) {
if (homer.hasOwnProperty(property)) {
const li = document.createElement('li');
const text = document.createTextNode(
`${property}: ${homer[property]}`
);
li.appendChild(text);
ul.appendChild(li);
console.log(`${property}: ${homer[property]}`);
}
}
Then remove the if
statement and console.log
:
for (const property in homer) {
const li = document.createElement("li");
const text = document.createTextNode(`${property}: ${homer[property]}`);
li.appendChild(text);
ul.appendChild(li);
}
And instead of directly looping over our homer
object, we can convert it to an array using the entries()
method:
for (const property in Object.entries(homer) ) {
// ...
}
This example will result in the values of undefined
in the browser. This may not be obvious at first why we see this, but this is because of the type of loop we are using. This is a for...in
loop, which is used on objects, and now we are converting homer
to be an array.
for...of
loopThis means we must use a for...of
loop:
for (const property of Object.entries(homer)) {
// ...
}
Don't worry about the undefined value in the browser, we will handle below.
And now, since we are dealing with arrays containing two values, which is the key/value pair, we can use destructuring to store these two values into variables:
for (const [key, value] of Object.entries(homer)) {
Finally, these two variables can be used to construct our text node:
for (const [key, value] of Object.entries(homer)) {
const li = document.createElement("li");
const text = document.createTextNode(`${key}: ${value}`);
li.appendChild(text);
ul.appendChild(li);
}
This is another good way of looping which does not involve the prototype, and if we want to, we can access the keys or the values individually:
console.log(Object.keys(homer));
console.log(Object.values(homer));
We often see these used in if
statements like this:
if (Object.keys(homer).length > 0) {
// do something
}
This checks if an object is not empty before doing something, and it just depends on if you want the key, the value or to use both.