109

I have turned on the Chrome flag for experimental ECMAscript 6 features, one of which is Set. As I understand, the details of Set are broadly agreed upon by the spec writers.

I create a set a and add the string 'Hello'

a = Set();
a.add('Hello');

but how do I iterate over the elements of a?

for(let i of a) { console.log(i); }

gives "SyntaxError: Illegal let declaration outside extended mode"

for(var i of a) { console.log(i); }

gives "SyntaxError: Unexpected identifier"

for(var i in a) { console.log(i); }

gives Undefined

Is it possible to iterate over of a set in Chrome 26?

Randomblue
  • 112,777
  • 145
  • 353
  • 547
  • 2
    [Looks like for-of](http://kangax.github.io/es5-compat-table/es6) is only supported in Firefox currently... – Mark Rushakoff May 06 '13 at 14:49
  • [How to implement a Set in JavaScript](http://www.javascriptexamples.org/2011/01/17/how-to-implement-a-set-in-javascript/) – NullPointerException May 06 '13 at 14:56
  • can you use this: http://jsclass.jcoglan.com/set.html – Bass Jobsen May 06 '13 at 15:14
  • See [Browser compatibility for `Set.prototype[@@iterator]()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/@@iterator#browser_compatibility) in the MDN docs. – Wyck Oct 24 '21 at 04:16

11 Answers11

78

A very easy way is to turn the Set into an Array first:

let a = new Set();
a.add('Hello');
a = Array.from(a);

...and then just use a simple for loop.

Be aware that Array.from is not supported in IE11.

andyrandy
  • 72,880
  • 8
  • 113
  • 130
  • 2
    Also, it has a second, optional parameter which is a mapping function to call on every element, i.e: `a = Array.from(a, e => e.length)`. – Adamantium Feb 02 '18 at 08:11
43

There are two methods you can use. for...of and forEach

let a = new Set();
a.add('Hello');

for(let key of a) console.log(key)

a.forEach(key => console.log(key))
Avadhut Thorat
  • 997
  • 11
  • 7
39

Upon the spec from MDN, Set has a values method:

The values() method returns a new Iterator object that contains the values for each element in the Set object in insertion order.

So, for iterate through the values, I would do:

var s = new Set(['a1', 'a2'])
for (var it = s.values(), val= null; val=it.next().value; ) {
    console.log(val);
}
bizi
  • 3,398
  • 2
  • 27
  • 28
  • 2
    When the iteration would be stopped then? According to the docs, StopIteration would be thrown. Using an exception for stopping the iteration is an awful solution. – Anton Pilyak Feb 21 '18 at 13:00
  • 1
    If you are referring to MDN doc about Iterator, I am not sure if their doc is still accurate, they also has a Warning on the page. The iterator will stop advancing once it reaches the end. – bizi Feb 28 '18 at 02:00
  • althought it worked for me, i didn't get why the for loop has only 2 statements, like why its' not '''var it = s.values(), val= null; ; val=it.next().value''' – codemonkey Oct 31 '21 at 16:01
32

I use the forEach(..); function. (documentation)

Samuel Diogo
  • 689
  • 10
  • 13
FranXh
  • 4,481
  • 20
  • 59
  • 78
  • 4
    I can't be cause I want to call 'await of an async function from my loop. – Kris May 29 '18 at 22:32
  • @Kris does `forEach(async () => await stuff())` not work? – flash Oct 02 '19 at 09:45
  • 4
    This question/answer https://stackoverflow.com/questions/37576685/using-async-await-with-a-foreach-loop explains it better than I could. But basically, foreach will work in a sense, but not how you expect it to. The foreach will not wait and execute your blocks of code sequentially. It fires them of in parallel. Maybe that could be what you want, but its not really equivalent to a for loop. – Kris Oct 02 '19 at 22:29
  • For Asynchronous code use Promise.all(loop here) – Param Mittal Jun 10 '23 at 02:41
8

The of operator doesn't appear to be currently supported in Chrome. It seems that only FireFox versions 13 through 18 support it. It also appears that none of the browsers actually support Set although the page does say that some of the tests represent existence and not full functionality or coherence. So it might be that Set is partially implemented in Chrome.

Vivin Paliath
  • 94,126
  • 40
  • 223
  • 295
8

You can also use the spread operator to convert a Set into an array (an alternative to Array.from(yourSet)).

const mySet = new Set();

mySet.add('a');
mySet.add('b')

const iterableSet = [...mySet];
// end up with: ['a', 'b']

// use any Array method on `iterableSet`
const lettersPlusSomething = iterableSet.map(letter => letter + ' something');
Sean Watters
  • 81
  • 1
  • 2
6

A simple functional approach is to just use forEach

const mySet = new Set([1, 2, 3])
mySet.forEach(a => { console.log(a) })
// 1 2 3
jpthesolver2
  • 1,107
  • 1
  • 12
  • 22
5

Even if the syntactic sugar for iteration hasn't been implemented yet, you can probably still use iterators.

http://www.2ality.com/2012/06/for-of-ff13.html explains

The special method __iterator__ returns an iterator object. Such an object has a method next() that either returns the next element in the current iteration sequence or throws StopIteration if there are no more elements.

So you should be able to iterate over the set using

for (var it = mySet.__iterator__();;) {
  var element;
  try {
    element = it.next();
  } catch (ex) {
    if (ex instanceof StopIteration) {
      break;
    } else {
      throw ex;
    }
  }
  // Do something with element
}

You can also define a functional version of for…of like

function forOf(collection, f) {
  // jQuery.each calling convention for f.
  var applyToElement = f.bind(/* this */ collection, /* index */ void 0);
  for (var it = collection.__iterator__();;) {
    var element;
    try {
      element = it.next();
    } catch (ex) {
      if (ex instanceof StopIteration) {
        break;
      } else {
        throw ex;
      }
    }

    // jQuery.each return convention.
    if (applyToElement(element) === false) { break; }
  }
}
Mike Samuel
  • 118,113
  • 30
  • 216
  • 245
  • 1
    Thanks. It's a little yucky, though. – Randomblue May 06 '13 at 16:18
  • 3
    @Randomblue, Yeah. Syntactic sugar is meant to gloss over all that, but often different people implement the syntax support in the parser than implement the library code so you get releases with half of a feature. When it's the syntax that lags you just have to desugar it yourself which requires seeing how sausage is made. – Mike Samuel May 06 '13 at 16:24
  • There is no such `__iterator__` method in the latest Node v0.11.4. – Randomblue Jul 13 '13 at 09:46
2

this worked for me

mySet.forEach(async(item) =>{
   await doSomething(item)
 })
James Wong
  • 4,529
  • 4
  • 48
  • 65
nik.ss
  • 81
  • 1
  • 8
1
let set = new Set();
set.add(1);
set.add(2);

// This will be an array now, now you can loop normally.
console.log([...set]);
Vasanth
  • 212
  • 1
  • 8
  • 2
    Please don't post only code as answer, but also provide an explanation what your code does and how it solves the problem of the question. Answers with an explanation are usually more helpful and of better quality, and are more likely to attract upvotes. – Dima Kozhevin Jul 31 '20 at 10:30
  • 1
    This will create a new array our of set. Make sure you understand that before use. – ruX Dec 06 '20 at 01:27
-1

@bizi's answer is close but it did not work for me. This worked on Firefox:

var s= new Set([1,2]),
     it = s.values();
 for (var val= it.next().value; val=it.next().value;) {
     console.log("set: "+val);
 }
Community
  • 1
  • 1
Tech
  • 57
  • 8