How does a function know how to take the elements of an array if they are not being passed to the function?

Asked

Viewed 107 times

1

Hello, the following code is correct, but I would like to understand one thing:

const Carros = ['Mercedes', 'Ferrari', 'BMW']

function imprimir(nome, indice){

    console.log(`${indice + 1}. ${nome}`)

}

Carros.forEach(imprimir)

When I pass the parameter name, and call it in console.log(), how my function knows that this is the name of the given cars on array? At no time did I pass such information as name?

2 answers

6

The implementation of forEach() that’s how. Internally she calls a function that she doesn’t yet know what it is, but she knows which contract that function should have, i.e., she knows what that function should return (in which case it should return nothing) and knows what arguments she should pass on, so it can call the function without problems and it will call in a proper way. It is your responsibility to create a function that follows these expected contracts and pass to it, in case you have created a function called imprimir() and that has two parameters, one of them is the value of an element and the other is an index of that element, in case you gave the names nome and indice, but could have given any name. Obviously you have to use this in function in a way that makes sense, and you did.

This thing you did is called callback, you say what should be called and follow an established contract. I will not go into detail about why the answer linked there speaks very well how this mechanism works.

Just a hint, in general this is cute, but if you do not have a very important reason should not use, not spi because it is slower, but also because it is less powerful and more confusing. This is a case that the for would work better, actually almost 100% of the use of forEach() It is not necessary, people use because they want to make fun without understanding the reason and complications of it. Today not even the fact of doing in a row serves much, because the same can be done with even fewer lines.

Roughly speaking that forEach() it would be something like that:

function foreach(array, func) {
    for (let key in array) func(array[key], key);
}
function imprimir(nome, indice) {
    console.log(`${indice + 1}. ${nome}`);
}
const carros = ['Mercedes', 'Ferrari', 'BMW'];
foreach(carros, imprimir);

Or you can just do this:

const carros = ['Mercedes', 'Ferrari', 'BMW'];
for (let indice in carros) console.log(`${indice + 1}. ${carros[indice]}`);

I put in the Github for future reference.

  • 2

    I see the opposite in relation to the use of forEach: if you do not have a strong reason for the performance or flexibility of for imperative, I prefer the declarative version because it is more readable. Readability, where I have worked, is the first goal, as long as it does not negatively (sensitively) interfere in performance

  • 1

    legibility ends up being subjective, there was a time when no one thought such a thing readable. And more readable is not, is more cute, in some scenarios makes little difference and precisely why I prefer what is more obvious, for me readable is to show what you do and not hide, unless it is minor detail. In most situations it even gets shorter, there are cases that is bad or impractical, not to mention performance. Why use two forms if one does the job well? Why keep key? For me legible is what you always do.

5


Whenever in doubt, see documentation, typically the MDN.

The documentation specifies the method forEach as follows:

Syntax:

arr.forEach(callback(currentValue [, index [, array]])[, thisArg]);

Note that the forEach gets a callback, i.e., a function only. Looking at your code has exactly that:

Carros.forEach(imprimir)
                   ^---- callback

Then this function passed will receive several values as arguments. Let’s look at the documentation again:

callback

Function to execute on each element, taking three arguments:

    currentValue

    The current value of the element being processed in the array.

    index

    Optional The index of the current element being processed in the array.

    array

    Optional The array foreach() is being applied.

So taking your job:

function imprimir(nome, indice){

You see that the parameter nome corresponds to the currentValue indicated in the documentation, and indice at the index. I remind that the parameters can have the name you want, because they are assigned by order and not by name.

If you needed you could also access the array itself, adding one more parameter for this:

function imprimir(nome, indice, array){

These values are passed to their function by the forEach, without you having to do more for it. Just have to interpret them and execute the intended logic.

As a matter of curiosity, here is an example of the implementation of forEach (put as meuForEach, to make clear):

//exemplo de implementação do forEach. 
//O Array.prototype é para que a função fique no objeto Array com o nome meuForEach
Array.prototype.meuForEach = function(callback) {
    //dentro do array o this refere o proprio array
    for (let i = 0; i < this.length; i++){ 
        //chamando sua função(callback) com o elemento, a posição e o array
        callback(this[i], i, this);  
    }
};

//o mesmo código que você ja tinha mas agora usando o meuForEach
const Carros = ['Mercedes', 'Ferrari', 'BMW']

function imprimir(nome, indice){
    console.log(`${indice + 1}. ${nome}`)
}

Carros.meuForEach(imprimir) //meuForEach em vez de forEach

Browser other questions tagged

You are not signed in. Login or sign up in order to post.