JavaScript "New Array(N)" and "Array.Prototype.Map" Weirdness

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

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.

Why is Array.map returning different results?

Array(n) creates an array of length n, but the array has no values in it so there is nothing to map over.

Basically, this:

const a = Array(n);

is the same as:

const a = [];
a.length = n;

This is why the created array has no elements in it. Attempting to map it will do nothing since there are no values to map.

You can, however, convert that empty array to an array of undefined values. This can be done in two ways:

One is using the spread operator as you have done:

[...Array(n)] // creates new array [undefined, undefined, undefined ...] n times

The other, more commonly used, is .fill(), which sets its parameter as the value for all the indices of the array. To fill with undefined, do:

Array(n).fill() // fills array with [undefined, undefined, undefined ...] n times

An array of undefined, unlike an empty array, has elements and can therefore be mapped:

[undefined, undefined, undefined].map(x => 1) // [1, 1, 1]

So you can first convert your empty array to an array of undefined, and then map it like so:

Array(n).fill().map(x => 1)

If you want to fill the array with the same element in each position like in this example, you can simply pass it in to fill without needing to map the array:

Array(n).fill(1)

How does `new Array(5).map()` work?

Array.apply(null, Array(5)) actually fills the array (or array-like object) that you pass as the second argument with the value of the first argument you pass in, as can be seen in the MDN Docs.

new Array(5) is just initializing an array with it's length property set to the argument of 5. Again, as can be seen in the MDN docs:

If the only argument passed to the Array constructor is an integer between 0 and 232-1 (inclusive), this returns a new JavaScript array with its length property set to that number (Note: this implies an array of arrayLength empty slots, not slots with actual undefined values).

Nested Array.prototype.map

In the end, I restructured the way the product options are added to the cart:

So when I check or uncheck boxes, my child component will pass the same option object like before:

let option = {
groupId: groupId,
groupName: groupName,
optionId: optionId,
optionName: optionName,
optionPrice: optionPrice,
}

The parent function receives the option object and builds the object structure to be appended to the add to cart item from the child component:

let object = {
groupId: option.groupId,
groupName: option.groupName,
groupOptions: [{
optionId: option.optionId,
optionName: option.optionName,
optionPrice: option.optionPrice
}]
};

Before doing that, it checks if the group already exists, if it does then it just appends the option object into groupOptions:

let currentOption = {
optionId: option.optionId,
optionName: option.optionName,
optionPrice: option.optionPrice
}

Now I just render it back out as a simple nested array.prototype.map and everything works good.

Map returns Empty statement array

you can do something like this

function getDaysArray(days) {
return Array.from({length: days}).map((_, i) => i + 1)

}

console.log(getDaysArray(31))

Unable to create and map through an array using new Array

You need to fill the array before mapping, as map ignores empty slots.

new Array(5).fill().map(num => <input />)

However, Array.from would be more suitable in this case.

Array.from({length: 5}, ()=> <input />)

Array.map doesn't seem to work on uninitialized arrays

If you'd like to fill an array, you can use Array(5).fill() and the methods will then work as expected--see the alternate related answer from aasha7. Older pre-fill approaches include:

Array.apply(null, new Array(5)).map(function() { return 0; });
// [ 0, 0, 0, 0, 0 ]

After some reading one of the posts linked in the comments, I found this can also be written as

Array.apply(null, {length: 5}).map(function() { return 0; });

However, trying to use .map on undefined values will not work.

x = new Array(10);
x.map(function() { console.log("hello"); });

// so sad, no "hello"
// [ , , , , , , , , , ]

.map will skip over undefined values :(

forEach is not a function error with JavaScript array

First option: invoke forEach indirectly

The parent.children is an Array like object. Use the following solution:

const parent = this.el.parentElement;

Array.prototype.forEach.call(parent.children, child => {
console.log(child)
});

The parent.children is NodeList type, which is an Array like object because:

  • It contains the length property, which indicates the number of nodes
  • Each node is a property value with numeric name, starting from 0: {0: NodeObject, 1: NodeObject, length: 2, ...}

See more details in this article.


Second option: use the iterable protocol

parent.children is an HTMLCollection: which implements the iterable protocol. In an ES2015 environment, you can use the HTMLCollection with any construction that accepts iterables.

Use HTMLCollection with the spread operatator:

const parent = this.el.parentElement;

[...parent.children].forEach(child => {
console.log(child);
});

Or with the for..of cycle (which is my preferred option):

const parent = this.el.parentElement;

for (const child of parent.children) {
console.log(child);
}


Related Topics



Leave a reply



Submit