How to Iterate Over the Elements of a Set in JavaScript
A Set in JavaScript is a collection of unique values that preserves insertion order. A fundamental task when working with a Set is to iterate over its elements to read, process, or display them. Modern JavaScript provides two primary, idiomatic ways to do this: the for...of loop and the forEach() method.
This guide will demonstrate both of these methods, explain their key differences, and provide a clear recommendation on which one to use for different scenarios.
The Core Method (Recommended): The for...of Loop
The for...of loop is the modern, standard, and most flexible way to iterate over any iterable object in JavaScript, including Set objects. Its syntax is clean, readable, and it supports control flow statements like break and continue.
For example, you have a Set and you want to process each of its elements.
// Problem: Log each item in the set to the console.
const mySet = new Set(['apple', 'banana', 'cherry']);
Solution:
let mySet = new Set(['apple', 'banana', 'cherry']);
for (let item of mySet) {
console.log(item);
}
Output:
apple
banana
cherry
This is the recommended best practice for most iteration needs.
An Alternative Method: Set.prototype.forEach()
Like arrays, Set objects also have a forEach() method. This is a good choice for a functional programming style, especially when you don't need to break out of the loop early.
let mySet = new Set(['apple', 'banana', 'cherry']);
mySet.forEach(item => {
console.log(item);
});
Output:
apple
banana
cherry
The callback function you provide to forEach() is called once for each element in the Set, in insertion order.
Note on the forEach Callback Signature: The full callback signature is (value, key, set). For Set objects, the key is the same as the value, which is a bit redundant but keeps the method consistent with the Map.forEach() signature.
mySet.forEach((value, key) => {
console.log(value === key); // Output: true, true, true
});
for...of vs. forEach(): Key Differences and When to Use Each
While both methods achieve iteration, they have crucial differences that determine which one is better for your specific use case. for...of is generally more powerful.
| Feature | for...of Loop | forEach() Method |
|---|---|---|
| Control Flow | Supports break and continue. You can exit the loop early or skip an iteration. | Does not support break or continue. It will always run to completion for all elements. |
| Async/Await | Works intuitively with await. The loop will pause for each asynchronous operation. | Does not wait for promises. If you use an async callback, forEach will not wait for it to complete before starting the next iteration. |
| Readability | Generally considered cleaner and more direct for simple loops: for (const item of iterable). | Can be more concise for functional chaining, but the callback adds a layer of nesting. |
Rule of Thumb:
- Use
for...ofas your default choice. It is more powerful and flexible. - Use
forEach()when you have a simple, synchronous operation that you want to apply to every single element without exception.
Practical Example: Finding and Breaking the Loop
This is a classic scenario where for...of is the only correct choice. The script needs to find a specific element in a Set and stop searching as soon as it's found.
let permissions = new Set(['READ', 'WRITE', 'EXECUTE', 'DELETE']);
function hasPermission(permissionToCheck) {
for (let permission of permissions) {
console.log(`Checking: ${permission}`);
if (permission === permissionToCheck) {
return true; // Found it, exit the function (and the loop)
}
}
return false; // Did not find it after checking everything
}
console.log(hasPermission('WRITE'));
Output:
Checking: READ
Checking: WRITE
true
This is far more efficient than a forEach() loop, which would have needlessly continued checking "EXECUTE" and "DELETE" even after the item was found.
Conclusion
Iterating over a Set in JavaScript is simple with modern syntax, but choosing the right method is important for writing clean and efficient code.
- The
for...ofloop is the recommended best practice for most situations. It is readable, flexible, and correctly handles control flow (break,continue) andasync/await. - The
forEach()method is a good alternative for simple, synchronous operations that must be applied to every element in theSet.
By defaulting to for...of, you ensure your code is ready to handle more complex logic like early exits or asynchronous operations.