JavaScript "new Array(n)" and "Array.prototype.map" weirdness
Solution 1
It appears that the first example
x = new Array(3);
Creates an array with a length of 3 but without any elements, so the indices [0], [1] and [2] is not created.
And the second creates an array with the 3 undefined objects, in this case the indices/properties them self are created but the objects they refer to are undefined.
y = [undefined, undefined, undefined]
// The following is not equivalent to the above, it's the same as new Array(3)
y = [,,,];
As map runs on the list of indices/properties, not on the set length, so if no indices/properties is created, it will not run.
Solution 2
I had a task that I only knew the length of the array and needed to transform the items. I wanted to do something like this:
let arr = new Array(10).map((val,idx) => idx);
To quickly create an array like this:
[0,1,2,3,4,5,6,7,8,9]
But it didn't work because: (see Jonathan Lonowski's answer a few answers beneath)
The solution could be to fill up the array items with any value (even with undefined) using Array.prototype.fill()
let arr = new Array(10).fill(undefined).map((val,idx) => idx);
console.log(new Array(10).fill(undefined).map((val, idx) => idx));
Update
Another solution could be:
let arr = Array.apply(null, Array(10)).map((val, idx) => idx);
console.log(Array.apply(null, Array(10)).map((val, idx) => idx));
Solution 3
With ES6, you can do [...Array(10)].map((a, b) => a)
, quick and easy!
Solution 4
ES6 solution:
[...Array(10)]
Doesn't work on typescript (2.3), though
Solution 5
From the MDC page for map
:
[...]
callback
is invoked only for indexes of the array which have assigned value; [...]
[undefined]
actually applies the setter on the index(es) so that map
will iterate, whereas new Array(1)
just initializes the index(es) with a default value of undefined
so map
skips it.
I believe this is the same for all iteration methods.
Related videos on Youtube
rampion
Mathematician, programmer, and researcher; with interests in algorithmic design, software engineering theory, and massively parallel computing. I'm also a keyboard junkie and an aspiring language nerd.
Updated on November 11, 2021Comments
-
rampion over 2 years
I've observed this in Firefox-3.5.7/Firebug-1.5.3 and Firefox-3.6.16/Firebug-1.6.2
When I fire up Firebug:
var x = new Array(3) console.log(x) // [undefined, undefined, undefined] var y = [undefined, undefined, undefined] console.log(y) // [undefined, undefined, undefined] console.log( x.constructor == y.constructor) // true console.log( x.map(function() { return 0; }) ) // [undefined, undefined, undefined] console.log( y.map(function() { return 0; }) ) // [0, 0, 0]
What's going on here? Is this a bug, or am I misunderstanding how to use
new Array(3)
?-
RussellUresti about 13 yearsI don't get the same results you see from the array literal notation. I still get undefined instead of 0. I only get the 0 result if I set something like
var y = x.map(function(){return 0; });
, and I get this for both the new Array() method and the array literal. I tested in Firefox 4 and Chrome. -
Hashbrown over 4 yearsalso busted in Chrome, this might be defined in the language, although it makes no sense so I really hope it isnt
-
-
Lightness Races in Orbit about 13 yearsIt's defined to be broken? It's designed to produce an array of three elements that will always be
undefined
for ever? -
Pointy about 13 yearsYes, that's correct, except for the "forever" part. You can subsequently assign values to the elements.
-
gen_Eric about 13 yearsThat's why you should use
x = []
instead ofx = new Array()
-
Martijn about 13 yearsFrom MDC (emphasis mine): "
map
calls a provided callback function once for each element in an array, in order, and constructs a new array from the results.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." In this case,x
's values have not explicitly assigned values, whereasy
's were assigned, even if it was the valueundefined
. -
Trevor Norris over 11 yearsSo is it a JavaScript failing that it's impossible to check whether it's an undefined pointer, or a pointer to undefined? I mean
(new Array(1))[0] === [undefined][0]
. -
David Mårtensson over 11 yearsWell, an array of undefined is different from an array of pointers to undefined objects. An array of undefines would be like an array of null values, [null, null, null] while an array of pointers to undefined would be like [343423, 343424, 343425] poining to null and null and null. The second solutions have real pointers pointing to memory addresses while the first do not point anywhere. If that is a failing of JS is probably a matter o discussion, but not here ;)
-
squid314 about 9 years@TrevNorris, you can easily test that with
hasOwnProperty
unlesshasOwnProperty
itself has a bug:(new Array(1)).hasOwnProperty(0) === false
and[undefined].hasOwnProperty(0) === true
. In fact, you can do the exact same within
:0 in [undefined] === true
and0 in new Array(0) === false
. -
Ruhee Jaiswal about 9 yearsTalking about "undefined pointers" in JavaScript confuses the issue. The term you're looking for is "elisions".
x = new Array(3);
is equivalent tox = [,,,];
, notx = [undefined, undefined, undefined]
. -
David Mårtensson about 9 yearsI never claimed that the two are equal, on the contrary, its that they are NOT equal I emphase, that in the first case the array has a size but no content and the mapping function cannot run but in the second there is objects even if they are undefined and map can run as long as you do not try to access the object. OP was confused by the fact that the two rendered the same output in firebug while not behaving the same in the map function.
-
Yann Eves about 8 yearsworth noting you don't need to state
undefined
in the.fill()
method, simplifying the code very slightly tolet arr = new Array(10).fill().map((val,idx) => idx);
-
Molomby almost 7 yearsPre-ES6 you can use
new Array(10).fill()
. Same result as[...Array(10)]
-
ibex almost 6 years
Array(10).fill("").map( ...
is what worked for me with Typescript 2.9 -
Admin almost 5 yearsWith large arrays the spread syntax creates issues so it's better to avoid
-
Admin almost 5 yearsSimilarly you can use
Array.from(Array(10))
-
Magnus about 4 yearsI'm curious. Under the hood (in C++ land, etc.), what is the pointer pointing to if it is an "undefined pointer"? Does javascript allocate a special location in memory that represents "being undefined".
-
Chungzuwalla almost 4 yearsor
[...Array(10).keys()]
-
vsync over 3 yearsI know how it works, but please add some explanation, for those who don't
-
Sebastien H. almost 3 yearsI would recommend @eden-landau 's answer, since it's a cleaner way of initializing an array
-
Sebastien H. almost 3 yearsThis is the cleanest answer to me.
-
Sebastian Simon over 2 yearsThe terminology is still wrong in this answer. The reason that
map
doesn’t execute its callback is thatnew Array(3)
doesn’t have an index property up to itslength
. The point abouthasOwnProperty
is relevant:map
will execute for every entry inObject.keys(array)
(or.values
or.entries
etc.). If that’s empty,map
will execute 0 times. This has nothing to do with “pointers”. The reasonnew Array(3)[0]
isundefined
is because that’s what non-existent properties produce. Good thing modern debugging tools make this difference more evident. “undefined object” is an oxymoron. -
Piliponful about 2 yearsThe answer is incorrect
-
Trevor Karjanis almost 2 yearsRemember to use return when mapping to an object. :X
Array.apply(null, Array(10)).map(() => { return {}; });
-
cstuncsik almost 2 years@TrevorKarjanis thanks for the hint but feels not relevant. Where do I need an object here?
-
Trevor Karjanis almost 2 years@cstuncsik You don't. You're returning an number
idx
. My comment is just to help anyone that followed your answer but needs to map to objects. -
Phil D. almost 2 years@TrevorKarjanis we're going way off topic here, but the crux of your statement is just how returned object literals work in a arrow functions: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
-
Trevor Karjanis almost 2 years@Phil D Yep! I've known that and still make the mistake every once in a while.