DEV Community 👩‍💻👨‍💻

Discussion on: Why you should use Array.some instead of 'for' loop or forEach?

Collapse
 
psiho profile image
Mirko Vukušić • Edited on

Hm, it is a nice introduction to array.some() but I don't think it's completely explained and some might pull wrong conclusions from this. Using "for" cannot be considered "wrong", especially not with explanation of why it would be wrong: "The problem with this approach is, this is not the right way to solve this problem.". So, it is wrong because it is wrong?

To be specific about array.some(), yes, it's hard to beat it in speed and simplicity. But it's also not hard to match it (in speed). What is left in that case is readability and simplicity of the code which makes it a clear winner in your example.
However, some might think that all of those "new" methods are always better and that "for" is incorrect, and that is not true. More often than not, new methods win in simplicity and readability but sacrifice speed. For most cases, speed difference is so small that it is unimportant, but when dealing with large arrays (and/or process them often), faster solution beats readable solution.

And again, it's not difficult to match "new" methods with "old" for-loops when it comes to speed. In fact, I don't know of a single case when you cannot match it with for-loops. New methods are never faster, they're just equally fast at best, and quite often... slower. So, for some performance oriented system, it's actually easier to always use for-loops and stop thinking if some of new methods is slower or equally fast... you just can never loose with for-loop in this case.

What I'm trying to say is that performance vs readability is not mentioned at all here, and naming "for" solution simply "wrong" is incorrect in my opinion. But yes, if you just don't need/want to care about performance then article is completely correct.

Example (benchmark) how to match performance of some() (and how NOT to try and match it) is here: jsbench.me/3ykr5dwv5l/1
It also serves as a good advocate to some(), because you can see it's highly optimized. i++ cannot beat it! You have to know about i-- trick to save that extra 7% (at least in Chrome)

Collapse
 
mazentouati profile image
Mazen Touati

I think some is confusing when introduced alone like in this article. It would be insightful if it's coupled with the contrasting function every.

I would like to add to what you've said that these all new methods are just new built-in functions in the Array's prototype. They are not language constructs. Hence, the looping constructs (for, while, etc.) have to be used anyway behind the scene.

Collapse
 
sannajammeh5 profile image
Sanna Jammeh

Behind the scenes V8 does not compile forEach, map, reduce etc to a for loop and then executes. It has its very own implementation within the runtime at the lowest possible level.

Only for polyfills where the engine does not have an implementation will you see a behind the scenes "for" or "while" loop.

Thread Thread
 
mazentouati profile image
Mazen Touati

Thank you for bringing this up. Indeed, V8 pre-compiles it to bytecode to enhance performance and to optimize memory usage. My comment made it sound like they're some kind of a library written in JS and being imported to your code to add new functions to the Array's protytpe. That's what I was thinking to be honest. After checking, it turns out V8 uses its own language V8 Torque and pre-compiles it to bytecode. Here's Array.some source code for example.

However, what I've tried to say is that it has to loop through the items at some point (even in the lowest level). Also, These optimations are not exclusive to the built-in functions. V8 will optimize your code too. For instance, most of the benchmarks I've consulted state that native for loops are faster than forEach, reduce, map etc.

The whole point was to point out that using For loops is not a wrong approach unlike what's being said in this Article.

Collapse
 
lukeshiru profile image
Luke Shiru

Generally there are performance gains from doing it with for, but from my point of view, readability is way more valuable.

If you run into a scenario in which the performance difference matters (like those arrays of 50000 items that folks love to mention when talking about performance), then the problem is not with the array method, but actually with data itself. Those volumes of data should be handled using streaming methods, or just splitting them into smaller chunks.

Still, I agree with you that the author should have said that the main benefit is that is a way nicer syntax, at the cost of a little bit of performance (which generally doesn't matter that much).

Collapse
 
psiho profile image
Mirko Vukušić

Yes, agree. It also needs to be said that often people overoptimize code for speed wasting readibility. In vast majority of cases it's absolutely not needed, especially not in places like this. But I'm ol school, started with assembler and only like 32 KB of memory so I got into habbit... Not to optimize every case, but to learn and know how things work and try to get good habbits, so relatively optimized code is written right from start. I admit that my treshold for wasting resources is lower :)
In practice, what I can think of are games, where each frame counts. Also, I do a lot of business apps, like erp, and sometimes I need to agregate thousands of records (like invoices) client side (because server side is external api). Splitting data when agreggating is not an option. In those cases I always go to for-loops, even if couple thousands are still not a huge reason to optimize. In thise cases, I "solve" readibility by extracting loops to helper functions which are properly named.

Collapse
 
luk492 profile image
Luka Kajtes

I totally agree with your comment. Plus this is the polyfill for the "some" implementation. Good old for, just sayin...

if (this == null) {
  throw new TypeError('Array.prototype.some called on null or undefined');
}

if (typeof fun !== 'function') {
  throw new TypeError();
}

var t = Object(this);
var len = t.length >>> 0;

for (var i = 0; i < len; i++) {
  if (i in t && fun.call(thisArg, t[i], i, t)) {
    return true;
  }
}

return false;
Enter fullscreen mode Exit fullscreen mode