jsguides

Set.prototype.values()

set.values()

The values() method returns a new Iterator containing all the values in the Set, in insertion order. Because Set stores only values (not key-value pairs), values() is effectively an alias for keys() and the default Symbol.iterator method. All three iterate the same sequence.

Syntax

set.values()

Return value

A new Iterator object that yields each value in the Set in insertion order. Because Sets do not have numeric indices, iterators are the standard way to walk through their contents sequentially. Every call to values() returns a fresh iterator that starts at the first element, so you can iterate multiple times without consuming anything permanently.

Examples

Using values() to iterate

const fruits = new Set(['apple', 'banana', 'cherry']);

for (const fruit of fruits.values()) {
  console.log(fruit);
}
// apple
// banana
// cherry

The loop visits values in the order they were added. Sets do not have numeric indices, so values() is the standard way to access elements sequentially. Once you have an iterator, a natural next step is to dump the values into an array so you can use array methods like map, filter, and reduce without altering the original Set.

Converting to Array

const set = new Set([1, 2, 3, 4, 5]);

// Using spread operator
const arr1 = [...set.values()];
console.log(arr1);
// [1, 2, 3, 4, 5]

// Using Array.from
const arr2 = Array.from(set.values());
console.log(arr2);
// [1, 2, 3, 4, 5]

Both [...set.values()] and Array.from(set) produce the same result, since spreading a Set already calls its default iterator. With the values in an array, you can apply any transformation pipeline — doubling a price list, summing totals, or chaining map-filter-reduce — without losing the deduplication guarantee the Set gave you up front.

Processing Set values

const prices = new Set([10, 20, 30, 40]);

// Double each value
const doubled = [...prices.values()].map(v => v * 2);
console.log(doubled);
// [20, 40, 60, 80]

// Sum all values
const sum = [...prices.values()].reduce((a, b) => a + b, 0);
console.log(sum);
// 100

Transformation pipelines like map and reduce are common, but filter is equally useful when you need to narrow a Set’s contents down by some criterion. The example below searches a Set of tags for entries longer than a threshold — something that would be awkward to express as a Set-only operation without first converting to an array.

Finding specific values

const tags = new Set(['javascript', 'python', 'rust', 'go']);

// Find values longer than 6 characters
const longNames = [...tags.values()].filter(t => t.length > 6);
console.log(longNames);
// ['javascript', 'python']

Converting to an array first lets you apply all the standard Array.prototype methods against Set contents without losing the uniqueness guarantees of the original Set. This approach works for simpler counts too — dropping a string into a Set and reading the array length is a fast, one-line way to count unique words without any manual deduplication logic.

Practical: unique word counting

const text = 'the quick brown fox jumps over the lazy dog';
const words = new Set(text.split(' '));

const wordCount = [...words.values()].length;
console.log(wordCount);
// 8

Counting unique words is a practical one-liner, but sometimes you need finer control over iteration — pausing, resuming, or pairing values from two sources. The iterator protocol supports this with next(), which advances one element at a time instead of dumping everything into a loop.

Using iterator directly

const set = new Set(['a', 'b', 'c']);
const vals = set.values();

console.log(vals.next().value);
// 'a'
console.log(vals.next().value);
// 'b'
console.log(vals.next().value);
// 'c'
console.log(vals.next().done);
// true

Calling next() manually is useful when you need to consume the iterator incrementally rather than all at once, for example when pairing Set values with values from another source. For the common case of applying multiple transforms to every element, chaining array methods through spread syntax is cleaner and more readable. The final example combines filter and map in a single pipeline.

Chaining array methods

const numbers = new Set([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);

const result = [...numbers.values()]
  .filter(n => n % 2 === 0)
  .map(n => n * n);

console.log(result);
// [4, 16, 36, 64, 100]

Relationship to keys() and Symbol.iterator

For a Set, all three of these are equivalent:

  • set.values() — returns an iterator over the values
  • set.keys() — also returns an iterator over the values (Sets have no separate keys)
  • The default Symbol.iterator method — also returns an iterator over the values

This design mirrors Map, which has distinct keys() and values(). For Set, the “key” and “value” are the same thing, so both methods produce identical output. The for...of loop uses the default iterator, which means iterating a Set directly and iterating set.values() are interchangeable.

const s = new Set([10, 20, 30]);
console.log([...s] + '');           // "10,20,30"
console.log([...s.values()] + '');  // "10,20,30"
console.log([...s.keys()] + '');    // "10,20,30"

Mutation during iteration

The iterator returned by values() is live, not a snapshot. Deleting a value before the iterator reaches it will cause the iterator to skip it. Adding new values after the iterator starts will also add them to the sequence. In practice, avoid mutating a Set while iterating it unless you have a specific reason to do so.

See Also