r/JavaScriptTips • • Jun 24 '19

Use Object.entries() to loop through the the keys and values in an object

This is from ES2017

const users = {
  'c1g6hhsus': {name: 'Matthias Broue', dob: '1990-05-04'},
  'uhwtpyce2': {name: 'Jenette Vix', dob: '1998-12-01'},
  'nvt89pzgx': {name: 'Osman Tragger', dob: '1989-12-26'},
  '9gcvl8lbj': {name: 'Tamara Islington', dob: '1993-09-18'},
};
const statements = Object.entries(users).map(([key, val]) => `<li>${val.name}'s user ID is ${key}.</li>`);
document.querySelector('.idStatements').innerHTML = `<ul>${statements.join('')}</ul>`;

If you wanted, you could also deconstruct val to just get name out:

const statements = Object.entries(users).map(([key, {name}]) => `<li>${name}'s user ID is ${key}.</li>`);

MDN: Object.entries()

8 Upvotes

2 comments sorted by

1

u/[deleted] Jun 24 '19

I'd like to point out that using .innerHTML() is against best practices and a serious security risk. In the example you provide, it would be better to insert the <ul>...</ul> into whatever .querySelector('.idStatements') returns via the use of .appendChild().

https://developer.mozilla.org/en-US/docs/Web/API/Node/appendChild

In fact, I'd do the same for adding the <li>...</li> elements to the <ul>...</ul> as opposed to building out a string.

1

u/OlanValesco Jun 24 '19

Well, if we're going for speed, then insertAdjacentHTML is speedier (something like 2x faster than appendChild). Here's a JSPerf if you want to run it yourself. innerHTML has problems like destroying all values, references, and event listeners that were part of those elements, and it's slow.

I wonder if creating a single template element, then just cloning that on each iteration would be faster? I think maybe only if you have a sizable block of HTML to parse (for example, see this Google page on Custom Components). If it's just an li with no attributes, for example, I would guess that doing document.createElement is the quicker way.

Anyway, I agree, there are much better ways than innerHTML! But for someone unfamiliar with Object.entries(), it might be easier for them to only see a few lines with otherwise familiar content.

Rewriting for efficiency I get:

const list = document.createElement('ul');
for (const [key, {name}] of Object.entries(users)) {
  list.insertAdjacentHTML('beforeend', `<li>${name}'s user ID is ${key}.</li>`);
}
const container = document.querySelector('.idStatements');
while (container.firstChild) container.removeChild(container.firstChild);
container.appendChild(list);

Versus the two lines in the original. For someone who's just learning Object.entries(), I would argue that they'll have an easier time processing two lines than seven (or five if you put the for loop on one line).

But now that you've commented there's some valuable discussion for someone interested in learning more :)