Frontend Development 10 min read

Master JavaScript Object Traversal: keys(), values(), entries() & Custom Iterators

This article explains the differences between Object.keys/values/entries and their array counterparts, shows how to use them for object property iteration, demonstrates creating custom iterator methods for plain objects, and compares iterator results with array returns, providing code examples and visual diagrams.

WeDoctor Frontend Technology
WeDoctor Frontend Technology
WeDoctor Frontend Technology
Master JavaScript Object Traversal: keys(), values(), entries() & Custom Iterators

Background

The story begins with a confusion when traversing arrays and object properties: whether to use obj.keys(), obj.values(), obj.entries() or the static methods Object.keys(obj), Object.values(obj), Object.entries(obj).

keys(), values(), entries() traversal methods

Native object structures do not support obj.keys(), obj.values(), or obj.entries(); only arrays, Map, Set, etc., have those methods. However, Object.keys(obj), Object.values(obj), and Object.entries(obj) can retrieve an object's own enumerable property names, values, or [key, value] pairs as arrays.

There are two versions of these methods:

ES5‑ES2017 introduced Object.keys, Object.values, and Object.entries, returning arrays of an object's own enumerable keys, values, or entries, which can be iterated with

for...of

.

ES6 added

entries()

,

keys()

, and

values()

for array‑like structures, returning an iterator object.

Key differences:

The call syntax differs: static methods vs. prototype methods.

The static methods return a true array, while the prototype methods return an iterator.

Q1: Object.keys, Object.values and Object.entries

These static methods operate on the Object prototype's constructor. The following diagram shows their placement in the prototype chain for a plain object:

For an array, the same three methods can be found both on the array prototype and higher‑level prototype constructors:

Thus,

Object.keys(arr)

calls the method defined on the top‑level prototype, while

arr.keys()

invokes the array’s own prototype method.

Q2: Enabling obj.keys(), obj.values() and obj.entries() on a plain object

By adding a custom iterator to an object, we can mimic array‑like traversal. The following code creates an object with its own

keys

method that returns an iterator:

<code>let objE = {<br/>  data: ['hello', 'world'],<br/>  keys: function() {<br/>    const self = this;<br/>    return {<br/>      [Symbol.iterator]() {<br/>        let index = 0;<br/>        return {<br/>          next() {<br/>            if (index < self.data.length) {<br/>              return { value: self.data[index++], done: false };<br/>            }<br/>            return { value: undefined, done: true };<br/>          }<br/>        };<br/>      }<br/>    };<br/>  }<br/>};</code>

The object now supports

Object.values(data)

and its own iterator. The diagram below illustrates the added

Symbol.iterator

:

Q3: Return differences – iterator vs. array

The static methods return arrays containing only the object's own enumerable properties. The iterator methods return an iterator object that can be consumed by

for...of

loops.

Using

for...in

can achieve similar results, but

for...of

works directly with iterators.

Iterator Overview

Four main collection‑like structures—Array, Object, Map, and Set—can be traversed via iterators. Native structures that implement the Iterator interface include Array, Map, Set, String, TypedArray, arguments, and NodeList.

Iterators provide a unified access mechanism for all iterable data structures, enabling

for...of

loops.

1. Traversing array‑like structures

When a

for...of

loop runs, it looks for the

Symbol.iterator

property. Any object with this property is considered iterable.

2. Getting an object's enumerable properties

Object.keys

,

Object.values

, and

Object.entries

return only the object's own enumerable properties. Plain objects are not iterable because they lack

Symbol.iterator

, so

for...of

throws a TypeError.

3. Using for...of

Introduced in ES6,

for...of

offers concise syntax, supports

break

,

continue

, and

return

, and works across all iterable structures.

To make a plain object iterable, we can implement

Symbol.iterator

as shown:

<code>// plain object<br/>const obj = {<br/>  foo: 'value1',<br/>  bar: 'value2',<br/>  [Symbol.iterator]() {<br/>    const keys = Object.keys(obj);<br/>    let index = 0;<br/>    return {<br/>      next: () => {<br/>        if (index < keys.length) {<br/>          return { value: this[keys[index++]], done: false };<br/>        } else {<br/>          return { value: undefined, done: true };<br/>        }<br/>      }<br/>    };<br/>  }<br/>};<br/>for (const value of obj) {<br/>  console.log(value); // value1 value2<br/>}</code>

This enables

for...of

to iterate over plain objects just like arrays.

JavaScriptIteratorkeysvaluesentriesObject Traversal
WeDoctor Frontend Technology
Written by

WeDoctor Frontend Technology

Official WeDoctor Group frontend public account, sharing original tech articles, events, job postings, and occasional daily updates from our tech team.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.