6

I'm want to quickly construct an array of n length using the array constructor Array() and then loop over the resulting array.

Per MDN's docs:

If the only argument passed to the Array constructor is an integer between 0 and 232-1 (inclusive), this returns a new JavaScript array with length set to that number. If the argument is any other number, a RangeError exception is thrown.

Presumably, executing Array(5) creates an array with a length of 5, which it does.

var arr = new Array(5);

console.log(arr); // [undefined x 5]
console.log(arr.length); // 5

However, when I try to loop over the resulting array and log out the values or the index, nothing happens.

arr.forEach(function(v, i) { console.log(v, i); });

// nothing logs to the console

Alternatively, if I use an array literal, and try to loop over the values, it logs as expected:

[undefined, undefined].forEach(function(v, i) { console.log(v, i); });

// undefined 0
// undefined 1

Why can't I loop over an array created by the Array constructor?


This answer explains some of the browser strangeness that occurs with map, example:

arr.map(function(v, i) { return i; }) // returns [undefined x 5]

But I'm particularly interested in why the forEach loop doesn't iterate at all over the values.

Community
  • 1
  • 1
Himmel
  • 3,629
  • 6
  • 40
  • 77
  • `[,,].forEach(console.log.bind(console, 'Log: '))` also seems broken :) – vp_arth May 27 '16 at 19:50
  • But `Array.apply(null, new Array(5)).forEach(console.log.bind(console))` ok – vp_arth May 27 '16 at 20:00
  • This is the same as [JavaScript “new Array(n)” and “Array.prototype.map” weirdness](http://stackoverflow.com/q/5501581/1529630), but with `forEach`. – Oriol May 27 '16 at 20:05
  • That question helps explain some of the strangeness, but doesn't illuminate the reason why `forEach` fails to iterate at all, as opposed to `map` which does iterate, but has unexpected values. – Himmel May 27 '16 at 20:15
  • It's the same problem, `map` is not iterated neither: `Array(5).map(function(){ alert("You won't see me") })` – Oriol May 27 '16 at 23:00

4 Answers4

4

I understand I am not answering to the question directly, bit still I believe this provides good information.

Check what Kyle Simpson said recently about this topic.

Basically,

console.log(new Array(5))  // Chrome: [undefinedx5] Firefox: [ <5 empty slots> ]

and

console.log([undefined, undefined, undefined, undefined, undefined]) // [ undefined, undefined, undefined, undefined, undefined ] 

are entirely different value types. And the browser is (kind of) lying to you when it says undefinedx5. Applying .map() over the first case will return nothing, while in the second case you can do operations with the undefined.

From the spec, ecma-262/5.1/#sec-15.4.2.2, the only thing new Array(5) does, is to create an object of class type Array with length property = 5. The literal array syntax, [], actually places the types (if you give it something) in the slots.

VRPF
  • 3,118
  • 1
  • 14
  • 15
3

That's because ES5 array methods skip missing indexes. That is, they iterate i from 0 to length-1, but at each iteration they check if the array has an i own property.

If you want it to work, you can use fill to create the indices.

var arr = new Array(5).fill();
arr.forEach(function(v, i) { console.log('arr['+i+'] = ' + v); });
Oriol
  • 274,082
  • 63
  • 437
  • 513
2

Looks like you have a typo in your code:

arr.forEach(functio(v, i) {

Use this instead:

arr.forEach(function(v, i) {

UPDATE

forEach() executes the provided callback once for each element present in the array in ascending order. It is not invoked for index properties that have been deleted or are uninitialized (i.e. on sparse arrays). MDN article

e_i_pi
  • 4,590
  • 4
  • 27
  • 45
  • Sorry, I noticed the typo and fixed it. The problem still exists, however. – Himmel May 27 '16 at 19:50
  • just a typo. issue is there. – vp_arth May 27 '16 at 19:50
  • Updated the answer. For each skips over undefined properties – e_i_pi May 27 '16 at 19:55
  • Knew it was forEach! Thanks for doing the legwork and looking the details of it up. – MTL-VRN May 27 '16 at 19:59
  • it's actually don't skip real `undefined`s – vp_arth May 27 '16 at 20:02
  • 1
    Array.map seems to have similarly strange behavior, running `arr.map(function(v, i) { return i; });` returns `[undefined x 5]` rather than the proper indices. Whereas running the same map call on an array literal with `undefined` works as expected. This leads me to believe it's an issue with the Array constructor array, not just the array methods themselves. – Himmel May 27 '16 at 20:02
  • Sorry, I meant uninitialised. TBH I've never used forEach(), I tend to go for for(). This was an exercise in research for me – e_i_pi May 27 '16 at 20:03
-1

I suspect that this may have to do with intricacies of the Javascript foreach loop, not the Array(int) constructor. Using a normal for loop:

for(var i = 0; i < arr.length; i += 1) {
  console.log(arr[i] + " " + i);
}

produced the desired result.

MTL-VRN
  • 393
  • 1
  • 14