6 ms·
I have a question: What does `for element of arr` buy me over `arr.forEach(element => ...)` I don't find the for...of syntax particularly appealing or useful,
by VeejayRampay 10y ago
I have a question:
What does `for element of arr` buy me over `arr.forEach(element => ...)`
I don't find the for...of syntax particularly appealing or useful, but I might be missing something. Is it a matter of preference?
- duckfruit 10y agofor...of is more flexible. While forEach is a method on Array.prototype, for...of is a consistent syntax that can be used in more places. For instance, iterables: function *myIterable (v) { while(--v) yield v } let launchCountdown = myIterable(60) for (let i of launchCountdown) console.log(`t minus ${i} seconds`) So in effect arrays can be thought of as iterables in ES6. So IMHO it allows for more consistent behavior with the way iterators in other languages like Java and C++
- VeejayRampay 10y agoAh, I see, good point. And how would you handle cases (that I end up using quite often) such as : arr.map(...).filter(...).forEach(...) which allows me to iterate over the filtered result? One would assign the result of filter to a variable and call for...of on that? EDIT: Also, I never saw any mention of for...of working for object literals (à la `for (let [key, value] of obj`), I suppose that's out of scope, correct?
- bzbarsky 10y ago> arr.map(...).filter(...).forEach(...) which allows me to iterate over the filtered result? Just like that. It would be pretty nice to have generic filter/map that can work on arbitrary iterables, but we don't have that right now. :( > Also, I never saw any mention of for...of working for object literals (à la `for (let [key, value] of obj`) for (let [key, value] of Object.entries(obj)) { } it's not in "ES6"/ES2015, but it's in ES2017 drafts and is implemented in Chrome and Firefox but so far not elsewhere. The need to do Object.entries instead of obj.entries() is annoying, but needed in case your literal has a property named "entries"... There's also Object.keys() and Object.values(), of course.
- pitaj 10y agoGenerics on iterables are super easy: function* map(iterator, mapper) { for (const elem of iterator) { yield mapper(elem); } } function* filter(iterator, filterer) { for (const elem of iterator) { if (filterer(elem)) { yield elem; } } } function forEach(iterator, eacher) { for (const elem of iterator) { eacher(iterator); } } function reduce(iterator, reducer, initial) { let current = initial; for (const elem of iterator) { current = reducer(current, elem); } return current; }
- bzbarsky 10y agoYes, but you have to have that boilerplate every time you want them instead of them just being around. It's not fatal, but is annoying.
- z3t4 10y agoIt's also useful if you want to call break or continue.
- addisonj 10y agofor...of isn't only for arrays. Anything that implements the Symbol.iterator functionality can use for..of, which is pretty nifty for some custom classes and also includes things like the new Map and Set collections, see: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#iterable https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe... However, even in just arrays there is arguably a benefit. Namely, an extra function being created and invoked with forEach. While in a JITing compiler, the performance difference between for...of and forEach might be negligible (or non existent), you can't always be sure what the JIT is going to do. For hotspots, I would probably prefer for..of
- VeejayRampay 10y agoAh, you're actually answering my question from above. I was wondering if there was a way to emulate the behaviour I've gotten accustomed to in Ruby vis à vis `Enumerable#each` where the (key, value) are yielded to the block passed to each. It doesn't seem to be possible to do that with object literals in JS, but you mention that Map would do (and it actually does, see [1]). Nice. [1] https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Map#Iterating_Maps_with_for..of https://developer.mozilla.org/en/docs/Web/JavaScript/Referen...
- bzbarsky 10y agoIf you're not in a JIT, for-of performance is going to be terrible too. Instead of creating a single function (which may not happen _anyway_ in the non-jit case, depending on how it's implemented) you now have to create an iterator result object for every single thing you get out of the iterator. In a JIT, forEach is actually _easier_ to optimize well (just need to inline the callback function, though of course that can fail for various reasons) than for-of (need to inline the calls to next() on the iterator, need to do escape analysis on the return value of next(), need to do scalar replacement on the return value of next; note that this is a strict superset of the work needed to optimize forEach). for-of can be nicer to read, and can work on arbitrary iterables. Those are its key strengths. Performance just isn't, unfortunately.
- tlrobinson 10y agofor-of works with any iterable. break/return/throw work as expected. I imagine (eventually if not already) for-of will be slightly more performant, but that's just a hunch. Personally I find the for-of syntax more readable.
- Klathmon 10y agoNot only that, but in the future when async/await lands (or right now if you are willing to compile and can put up with potential breakage), for-of becomes a godsend. The lack of inner functions means that you can await during part of a loop without a bunch of fuckery with the inner function with forEach.