DEV Community

Elango Sundar
Elango Sundar

Posted on

How many ways iterate the objects and arrays in javascript?

How many ways we can iterate the objects and arrays in javascript (ES6)?

Top comments (10)

Collapse
 
lexlohr profile image
Alex Lohr
// 1
array.forEach(() => { ... });
// 2
array.map(() => { ... });
// 3
array.reduce(() => { ... });
// 4
for (let i = 0; i < array.length; i++) { ... }
// 5
for (let i in array) { if (!array.hasOwnProperty(i)) continue; ... }
// 6
for (let i of array) { ... }
// 7 - do not try this at home!
let recursiveArrayHandling;
recursiveArrayHandling = (array, i) => {
  i = i || 0;
  const item = array[i];
  ...
  if (i + 1 < array.length) recursiveArrayHandling(array, i + 1);
};
recursiveArrayHandling(array);

I guess you could add a few more...

Collapse
 
qm3ster profile image
Mihail Malo

So long as you add return:

  if (i + 1 < array.length) return recursiveArrayHandling(array, i + 1);

You will be fine in Apple browsers :D

Collapse
 
lexlohr profile image
Alex Lohr

I knew I forgot something :-)

In any case, you won't be fine if the lenght of the array exceeds the one of the call stack.

Thread Thread
 
qm3ster profile image
Mihail Malo

Nuh-uh, bronathan! In fact, I assume that the logic / base case of the handling is void-returning.
The return here is purely to opt in to tail call optimization, which means you won't run out of stack :)
Once again, only implemented on Apple browsers at the moment, and probably staying that way.

Thread Thread
 
lexlohr profile image
Alex Lohr

Your misunderstanding might be resolved if you take the following as an example:

const array = new Array();
array.length = 1/0;
...

An extreme example, I concede, but as an exercise, you can try to figure out the call stack sizes for different JS engines (and AFAIK they're all smaller than the maximum number the 52bit mantissa of a Number can store).

Thread Thread
 
qm3ster profile image
Mihail Malo • Edited

Optimized tail calls don't grow the stack.

They're implemented with a goto, it's basically a loop.


{
  let i = 0
  const rec = () => (i++, rec())
  try {
    rec()
  } catch {}
  console.log(i)
}

On most browsers this will give you a number.
On Safari, Mobile Safari, and some embeddable runtimes like latest Duktape It will be an infinite loop.

Collapse
 
10secondsofcode profile image
Elango Sundar

@alex Nicely explained...Thanks..!

Collapse
 
lexlohr profile image
Alex Lohr

I didn't explain much, just wrote down the first few I could think of. I didn't even say why you should avoid recursion (you might overflow the call stack).

Thread Thread
 
qm3ster profile image
Mihail Malo

I'd be more wary of someone that does #5 :)
Or 2 or 3 for side effects.

Collapse
 
qm3ster profile image
Mihail Malo • Edited

Here's one more that doesn't overflow stack :)

const recursiveArrayHandling = (array, i = array.length) => {
  const item = array[--i]
  if (i % 4000) return recursiveArrayHandling(array, i)
  console.log(i, item)
  if (i) return setTimeout(recursiveArrayHandling, 0, array, i)
}
recursiveArrayHandling(new Array(1024 ** 3))

It's full of dumb hacks though, in real life I'd do this:

const recursiveArrayHandling = (array, fn) => {
  const { length } = array
  const innerFunc = (arr, i = 0) => {
    if (i === length) return
    arr[i] = fn(arr[i])
    if (i % 0x80) return innerFunc(arr, i + 1)
    if (i % 0x8000) console.log(i, arr[i]) // TODO: remove
    return setTimeout(innerFunc, 0, arr, i + 1)
  }
  innerFunc(array)
}

recursiveArrayHandling(new Array(1024 ** 3), x => x)

Why only 0x80? To have a lot of headroom, in case the fn is also something recursive.

The real problem here is that a 1024**3 array will quickly use up your memory, even if you start filling it with 0, undefined or even pointers to the same object. It can only exist as sparse.