Skip to content Skip to sidebar Skip to footer

Confused By Behavior Of `map` On Arrays Created Using `new`

I am confused by the results of mapping over an array created with new: function returnsFourteen() { return 14; } var a = new Array(4); > [undefined x 4] in Chrome, [, , ,

Solution 1:

When you create an array like so:

var arr1 = newArray( 4 );

you get an array that has a length of 4, but that has no elements. That's why map doesn't tranform the array - the array has no elements to be transformed.

On the other hand, if you do:

var arr2 = [ undefined, undefined, undefined, undefined ];

you get and array that also has a length of 4, but that does have 4 elements.

Notice the difference between having no elements, and having elements which values are undefined. Unfortunately, the property accessor expression will evaluate to the undefined value in both cases, so:

arr1[0]// undefinedarr2[0]// undefined

However, there is a way to differentiate these two arrays:

'0'in arr1 // false'0'in arr2 // true

Solution 2:

var a = newArray(4);

This defines a new array object with an explicit length of 4, but no elements.

var b = [undefined, undefined, undefined, undefined];

This defines a new array object with an implicit length of 4, with 4 elements, each with the value undefined.

From the docs:

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

For array a, there are no elements that have been assigned values, so it does nothing.

For array b, there are four elements that have been assigned values (yes, undefined is a value), so it maps all four elements to the number 14.

Solution 3:

new Array(len) creates an empty array, and does something different than filling it with undefined values: It sets its length to len. So, it translates to this code:

var newArr = [];
newArr.length = len;

Let's have some fun with newArr (assuming that len = 4):

newArr.length; //4
newArr[1] === undefined; //true
newArr.hasOwnProperty(1); //false

This is because while the is 4 items long, it does not contain any of these 4 items. Imagine an empty bullet-clip: It has space for, say, 20 bullets, but it doesn't contain any of them. They weren't even set to the value undefined, they just are...undefined (which is a bit confusing.)

Now, Array.prototype.map happily walks along your first array, chirping and whistling, and every time it sees an array item, it calls a function on it. But, as it walks along the empty bullet-clip, it sees no bullets. Sure, there are room for bullets, but that doesn't make them exist. In here, there is no value, because the key which maps to that value does not exist.

For the second array, which is filled with undefined values, the value is undefined, and so is the key. There is something inside b[1] or b[3], but that something isn't defined; but Array.prototype.map doesn't care, it'll operate on any value, as long as it has a key.

For further inspection in the spec:

Solution 4:

One additional answer on the behavior of console.log. Plain simple, the output is sugar and technically wrong.

Lets consider this example:

var foo = newArray(4),
    bar = [undefined, undefined, undefined, undefined];

console.log( Object.getOwnPropertyNames(bar) );
console.log( Object.getOwnPropertyNames(foo) );

As we can see in the result, the .getOwnPropertyNames function returns

["length"]

for the foo Array/Object, but

["length", "0", "1", "2", "3"]

for the bar Array/Object.

So, the console.log just fools you on outputting Arrays which just have a defined .length but no real property assignments.

Post a Comment for "Confused By Behavior Of `map` On Arrays Created Using `new`"