Foreach on Array of Undefined Created by Array Constructor

forEach on array of undefined created by Array constructor

Array(5) is essentialy equivalent to

var arr = []; 
arr.length = 5;

In javascript changing array's length doesn't set any values for it's numeric properties nor does it define those properties in the array object. So numeric properties are undefined instead of having undefined value. You can check it by using:

Object.keys(arr)

When iterating javascript iterates through numeric properties of the array, so if these don't exist, there is nothing to iterate over.

You can check it by doing:

var arr = Array(5)

//prints nothing
arr.forEach(function(elem, index, array) {
console.log(index);
});

arr[3] = 'hey'
//prints only 'hey' even though arr.length === 5
arr.forEach(function(elem, index, array) {
console.log(index);
});

The following code:

var arr = [undefined, undefined];

creates and array of length ===2 and sets the both numeric properties 0 and 1 to undefined.

Use forEach to loop over Array(n), array of undefined values

I understand I am not answering to the question directly, bit still I believe this provides good information.

Check what Kyle Simpson said recently about this topic.

Basically,

console.log(new Array(5))  // Chrome: [undefinedx5] Firefox: [ <5 empty slots> ]

and

console.log([undefined, undefined, undefined, undefined, undefined]) // [ undefined, undefined, undefined, undefined, undefined ] 

are entirely different value types. And the browser is (kind of) lying to you when it says undefinedx5. Applying .map() over the first case will return nothing, while in the second case you can do operations with the undefined.

From the spec, ecma-262/5.1/#sec-15.4.2.2, the only thing new Array(5) does, is to create an object of class type Array with length property = 5. The literal array syntax, [], actually places the types (if you give it something) in the slots.

Use forEach to loop over Array(n), array of undefined values

I understand I am not answering to the question directly, bit still I believe this provides good information.

Check what Kyle Simpson said recently about this topic.

Basically,

console.log(new Array(5))  // Chrome: [undefinedx5] Firefox: [ <5 empty slots> ]

and

console.log([undefined, undefined, undefined, undefined, undefined]) // [ undefined, undefined, undefined, undefined, undefined ] 

are entirely different value types. And the browser is (kind of) lying to you when it says undefinedx5. Applying .map() over the first case will return nothing, while in the second case you can do operations with the undefined.

From the spec, ecma-262/5.1/#sec-15.4.2.2, the only thing new Array(5) does, is to create an object of class type Array with length property = 5. The literal array syntax, [], actually places the types (if you give it something) in the slots.

JavaScript: use .map() and .forEach() on new Array() of undefinded

Try this:

const result = Array.apply(null, new Array(5)).map(() => ({name:''}));
console.log(result);

forEach loop quirky behavior with undefined values?

So apparently it is not assigning each value undefined, but only setting its length property to whatever is passed in the constructor.

Correct. (Provided you pass only a single argument and it's a number. If you pass a non-number, or pass more than one argument, they're used as elements for the array. So Array("3") results in ["3"]; Array(3, 4) results in [3, 4].)

This is not apparent when you log Array(n) to the console because it shows an array with n undefined values.

It depends on what console you use. The devtools in Chromium browsers show (3) [empty x 3] for exactly that reason, to differentiate between empty array slots and ones containing the value undefined.

So I guess my main question would be, are there other ways to execute forEach and map without filling the array or by using the quirky hack I mentioned earlier?

If you want forEach and map to visit elements of the array, they have to actually exist. Those methods (and several others) are defined such that they don't call your callback for empty slots in sparse arrays. If by "quirky hack" you mean [...Array(3)], that's also filling the array (and is fully-specified behavior: [...x] uses the iterator x provides, and the array iterator is defined that it yields undefined for empty slots rather than skipping them as forEach, map, and similar do). Doing that (spreading the sparse array) is one way to create an array filled with undefined (not empty) elements. Array.fill is another. Here's a third: Array.from({length: 3})

const a = Array.from({length: 3});
a.forEach(value => {
console.log(`value = ${value}`);
});

forEach with uninitialized array

I'm wondering if someone can explain this to me.

That is the spec.

forEach and its brethren ignore "holes" in sparse arrays. For more information, see this blog post.

From MDN:

forEach() executes the provided callback once for each element present in the array

The spec says the same thing.

Strange array constructor behavior with forEach

MDN on forEach

forEach() executes the provided callback once for each element present in the array in ascending order. It is not invoked for indexes that have been deleted or elided. However, it is executed for elements that are present and have the value undefined.

The way you're initializing the array does set it's length, but doesn't set the values in the array to anything, so forEach doesn't iterate over those elements:

If the argument len is a Number and ToUint32(len) is equal to len, then the length property of the newly constructed object is set to ToUint32(len).

Example:

var a = Array(5);
a.forEach(function(element){ console.log('First log:', element)});
a[2] = true;a[3] = undefined;
a.forEach(function(element){ console.log('Second log:', element)});
var b = [];b[999] = 'Foobar';
b.forEach(function(element){ console.log('Third log:', element)});

Why does `.forEach` work on dense arrays but not on sparse arrays?

  1. If they both have the same length, indexes, and values how is one iterable but the other isn't?

These functions are explicitly documented to perform this way. Both arrays are iteratable, but forEach/map/etc explicitly skips indices which are not in the array:

var sparse = new Array(3);
var dense = Array.apply(null, Array(3)); // See dense array link belo

1 in sparse; // false
1 in dense; // true

// Sparse can still be iterated over
sparse[100] = 'a'
sparse.forEach(function (n, i) { console.log(n, i) }); // a 100

  1. What is the reason for the difference?

Presumably an explicit decision was made to omit indices which don't exist


  1. What is the best way to determine if an array is sparse or dense?

You can use the following:

function isSparse(array) {
for (var i = 0; i < array.length; ++i) {
if (!i in array)
return true;
return false;
}

RE: Your comment

There has got be a reason for why [,,,] doesn't have indexes but [undefined, undefined, undefined] does.

There doesn't have to be a reason, that's just the way they're built. One has keys, the other doesn't.

Look:

Object.keys(Array(3)) // => []
Object.keys(['a','b']) // => ["0", "1"]

The forEach is undefined in a Javascript Class Method

DEFINITIVE SOLUTION

where were problem?
What's solution?
The #createMemberList() generate an array with more than 220 rows. Then, it's necessary wait a while for Of() method to process everything.
For it, it's must to use setTimeout() function in the method, like this:

setTimeout(()=>{
console.log(JSON.stringify(this.membersList))
},3000)

The code will to stay like this:

     const $INIT = {
GetMembers: class{
#listaOrdenadaItens;
#listaMembros;
#MemberListOfChurch;
membersList;
#linkGFile="https://cdn.jsdelivr.net/gh/OficialLeonardoLima/cdn@main/json_test.json";

constructor(ListFromGD){
if(typeof ListFromGD!=="undefined"&&ListFromGD!==null){
this.#linkGFile=ListFromGD;
}
this.#createMemberList();
setTimeout(()=>{
console.log(JSON.stringify(this.membersList))
},3000)

document.querySelector("#console").text=JSON.stringify(this.membersList)
}
/*Members List*/
Of(ChurchName){
/**Filters member data according congregation
* Usage: new $INIT.GetMembers().Of("ChurchName")
*/
this.#MemberListOfChurch=[];;
this.ChurchName=ChurchName;

setTimeout(()=>{
this.membersList.forEach((item, count) => {
console.log("Why this code don't appears in console?");
if (/^[a-zA-Z_À-Úà-ú\s]{2,50}$/.test(ChurchName)==true && ChurchName.toLocaleLowerCase() == item.congregacao.toLocaleLowerCase()) {

this.#MemberListOfChurch[count] = item;
}else{
console.log("Trys to check anyone error");
}

});
},3000);

return this.#MemberListOfChurch;
}
#getListaOrdenada (){
return [
/**Personal Informations */
"Nome Completo",
"Sexo",
"CPF",
"Data de Nascimento",
"RG",
"Orgão Emissor",
"UF_RG",
"Data de Expedição",
"Estado Civil",
"CONJUGE",
"Naturalidade",
"UF_NAT",
"NOME_PAI",
"NOME_MAE",

/**Schooling and ecclesiastical data */
"GRAU_INSTRUCAO",
"PROFISSAO",
"FUNCAO_ECLESIASTICA",
"LOCAL",
"UF_BATISMO",

/**Address informations */
"Endereco",
"cep",
"bairro",
"cidade",
"uf",
"congregacao",
"contact_number",
"whatsapp_number"

]
}
#createMemberList(){
var listaOrdenada = this.#getListaOrdenada();

/**Create an array */
var NewListMember = [];

var DadosMembros={};
/**
* Gets registered members list at system!
*/
this.#getJSON(this.#linkGFile).then(response=>{
response.values.forEach((item, i)=>{
/**Examina membro por membro aqui */
if(item[0]===undefined)return;

/**Creates a name for array of values: Ex: {"Complete Name" : "Leonardo Lima de Sousa"} */
listaOrdenada.forEach((ItemName,N)=>{
if(ItemName===undefined) return;
DadosMembros[ItemName]=item[N];
});


NewListMember[i] = DadosMembros;
DadosMembros={};
});
})

this.membersList=NewListMember;
}

#getJSON=async t=>{const r=await fetch(t);if(!r.ok)throw new Error(r.statusText);return r.json()};


}
}



Related Topics



Leave a reply



Submit