Confused By Behavior Of `map` On Arrays Created Using `new`
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:
new Array(len)
: http://es5.github.com/#x15.4.2.2Array.prototype.map
: http://es5.github.com/#x15.4.4.19 (pay close attention to step 8.b)
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`"