Question

I'm just learning how to use JS higher-order functions (map, forEach, reduce, etc), and have stumbled into confusion. I'm trying to write a simple 'range' function, but can't seem to populate my output array. This is the goal:

range(1, 4) // [1, 2, 3, 4]

I'm getting this:

[undefined × 4]

Here is my code:

 function range(num1, num2) {
      var rangeArr = new Array((num2 + 1) - num1);
      return rangeArr.map(function(e, i, arr) {return arr[i] = num1 + i});
    }

What am I missing here? As far as I can tell the problem appears to have something to do with the way I'm utilizing 'new Array', but beyond that I'm lost.

Oh, and here's the part that really confuses me. This works fine:

function bleck() {
    var blah = [1, 2, 3, 4];
    var x = 'wtf';
    return blah.map(function(e, i, arr) {return arr[i] = x})
}

["wtf", "wtf", "wtf", "wtf"]

Thanks!!

Was it helpful?

Solution

The forEach method iterates over the indices of the array. Interestingly enough, when you create a new array via new Array(n), it contains no indices at all. Instead, it just sets its .length property.

> var a = new Array(3);
> console.info(a)
[]
> console.info([undefined, undefined, undefined])
[undefined, undefined, undefined]

MDN describes forEach, and specifically states:

forEach executes the provided callback once for each element of the array with an assigned value. It is not invoked for indexes which have been deleted or elided.

Here's a neat technique to get an array with empty, but existing, indices.

var a = Array.apply(null, Array(3));

This works because .apply "expands" the elided elements into proper arguments, and the results ends up being something like Array(undefined, undefined, undefined).

OTHER TIPS

The array is defined with 4 entires each of which is undefined.

Map will not iterate over undefined entires, it skips them.

callback is invoked only for indexes of the array which have assigned values; it is not invoked for indexes that are undefined, those which have been deleted or which have never been assigned values.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map

When you create a new Array(x) it is creating what is called a sparse array, which might behave a bit differently, as you can see, some browsers will say [undefined x 20,"foo", undefined x 5] if you just set one value, and I believe it doesn't iterate over those values.

The problem is that map doesn't iterate undefined entries (*).

I suggest using a for loop instead:

var rangeArr = new Array((num2 + 1) - num1);
for(var i=0; i<=num2-num1; ++i)
    rangeArr[i] = num1 + i;
return rangeArr;

(*) With undefined entries I mean rangeArr.hasOwnProperty(i) === false, not to be confused with rangeArr[i] === void 0.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top