Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaScript "new Array(n)" and "Array.prototype.map" weirdness

People also ask

Does map create a new array JavaScript?

The map() method in JavaScript creates an array by calling a specific function on each element present in the parent array. It is a non-mutating method. Generally map() method is used to iterate over an array and calling function on every element of array.

Does array map return a new array?

The map() method returns an entirely new array with transformed elements and the same amount of data. In the case of forEach() , even if it returns undefined , it will mutate the original array with the callback .

Which is better array or map?

Map stores data in form of key : value which provides faster look ups as compared to an array. Map should be used when we have to maintain some relation between elements. eg : Count the occurrence of all the character in a given string and print key value pair for them.

Can you map an empty array JavaScript?

map() on empty array will not produces an error, but will return an empty array. Which is fine because empty array is a renderable item in react and won't produce error in render() and will not render the notes as there are no notes provided.


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 above)

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));

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.


With ES6, you can do [...Array(10)].map((a, b) => a) , quick and easy!


ES6 solution:

[...Array(10)]

Doesn't work on typescript (2.3), though


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.


The arrays are different. The difference is that new Array(3) creates an array with a length of three but no properties, while [undefined, undefined, undefined] creates an array with a length of three and three properties called "0", "1" and "2", each with a value of undefined. You can see the difference using the in operator:

"0" in new Array(3); // false
"0" in [undefined, undefined, undefined]; // true

This stems from the slightly confusing fact that if you try to get the value of a non-existent property of any native object in JavaScript, it returns undefined (rather than throwing an error, as happens when you try to refer to a non-existent variable), which is the same as what you get if the property has previously been explictly set to undefined.


In ECMAScript 6th edition specification.

new Array(3) only define property length and do not define index properties like {length: 3}. see https://www.ecma-international.org/ecma-262/6.0/index.html#sec-array-len Step 9.

[undefined, undefined, undefined] will define index properties and length property like {0: undefined, 1: undefined, 2: undefined, length: 3}. see https://www.ecma-international.org/ecma-262/6.0/index.html#sec-runtime-semantics-arrayaccumulation ElementList Step 5.

methods map, every, some, forEach, slice, reduce, reduceRight, filter of Array will check the index property by HasProperty internal method, so new Array(3).map(v => 1) will not invoke the callback.

for more detail, see https://www.ecma-international.org/ecma-262/6.0/index.html#sec-array.prototype.map

How to fix?

let a = new Array(3);
a.join('.').split('.').map(v => 1);

let a = new Array(3);
a.fill(1);

let a = new Array(3);
a.fill(undefined).map(v => 1);

let a = new Array(3);
[...a].map(v => 1);