Quatro métodos de pesquisa através de arrays em JavaScript

Em JavaScript, existem muitas maneiras úteis de encontrar itens em Arrays. Você pode sempre recorrer ao loop for básico, mas com ES6+ existem muitos métodos para fazer loop sobre um array e encontrar o que você precisa com facilidade.

Com tantos métodos diferentes, qual deles você usa e em qual caso? Por exemplo, ao pesquisar através de um array, você deseja saber se o elemento está na matriz? Você precisa do índice do elemento ou do elemento em si?

Com cada método diferente que vamos abordar, é importante entender que todos eles são métodos integrados em Array.prototype. Isso significa que você simplesmente precisa encadeá-los em um array com notação de ponto. Isso também significa que esses métodos não estão disponíveis em objetos ou qualquer outra coisa além de Arrays (embora haja sobreposição com Strings).

Veremos os seguintes métodos de Array:

  • Array.includes
  • Array.find
  • Array.indexOf
  • Array.filter

includes

const alligator = ["thick scales", 80, "4 foot tail", "rounded snout"];  alligator.includes("thick scales"); // returns true 

O método .includes() retorna um valor booleano e é perfeito para lhe dizer se um elemento existe ou não em um array. Ele dá uma resposta simples true ou false. Esta é a sintaxe básica:

arr.includes(valueToFind, [fromIndex]); 

Agora, como você pode ver em nosso exemplo, tínhamos apenas um parâmetro – o valueToFind. Este é o valor a ser pesquisado na matriz. O fromIndex opcional é um número, indicando de qual índice você deseja começar a procurar (o padrão é 0, então todo o array é pesquisado). Assim, como em nosso exemplo o item ‘thick scales’ está no índice 0, o seguinte seria false: alligator.includes('thick scales', 1); uma vez que ele começa a pesquisar a partir do índice 1 em diante.

Agora, há algumas coisas importantes a notar. Esse método .includes() usa comparação estrita. Isso significa que, a partir do exemplo acima, o seguinte retornaria false: alligator.includes('80'); isso é porque embora 80 == '80' seja verdadeiro, 80 === '80' é falso – diferentes tipos não passarão em uma comparação estrita.

find

Como o método.find() difere do método includes()? Se em nosso exemplo alterarmos o texto “includes” para “find”, obteremos esse erro:

Uncaught TypeError: thick scales is not a function 

Isso é porque o método find requer que uma função seja passada. Isso é porque o método find não irá usar o operador de comparação simples como o “includes()” faz. Em vez disso, ele irá passar cada elemento em sua função e ver se ela retorna true ou false. Assim, embora isso funcione: alligator.find(() => 'thick scales'); você provavelmente gostaria de colocar seu próprio operador de comparação na função para que ele retorne qualquer coisa relevante.

const alligator = ["thick scales", 80, "4 foot tail", "rounded snout"];  alligator.find(el => el.length < 12); // returns '4 foot tail' 

Essa função simples em nosso método find faz uma busca em cada elemento da array, com o alias 'el’ que atribuímos e termina ao encontrar o primeiro resultado verdadeiro. Em nosso caso, verdadeiro é ter uma propriedade de comprimento menor que 12 (os números não têm uma propriedade de comprimento). É claro que você poderia tornar essa função tão complexa quanto necessário, fazendo com que sua condição verdadeira atendesse às suas necessidades.

Observe também, isso não retornou true. O método find não retorna um booleano, mas, em vez disso, retorna o primeiro elemento .correspondente. Se não houver um elemento de correspondência – como em nada existe que atenda aos critérios definidos em sua função – ele irá retornar undefined. Observe também que ele retorna o primeiro, então se houver mais de um elemento no array que atende aos critérios, ele irá pegar apenas a primeira instância. Em nosso exemplo, se houvesse outra sequência de comprimento menor que 12 após '4 feet tall’ isso não alteraria nosso resultado.

Em nosso exemplo, usamos o callback apenas com um parâmetro. Pode-se também adicionar parâmetros para fazer referência ao índice do elemento atual. Outro parâmetro pode ser o array inteiro em si, mas eu acho que isso raramente é usado. Aqui está um exemplo usando o index:

alligator.find((el, idx) => typeof el === "string" && idx === 2); // returns '4 foot tall' 

Sabemos que em nosso array, existem 3 elementos diferentes que atendem à primeira condição (typeof el === 'string’). Se essa fosse a nossa única condição, ele retornaria a primeira, 'thick scales’. Mas a diferença é que, apenas um tem o índice de 2 e ele é '4 foot tall’.

Por falar em índices, um método de array similar é .findIndex(). Esse método também recebe uma função, mas como você pode imaginar, ele retorna o índice do elemento correspondente em vez do próprio elemento.

indexOf

const alligator = ["thick scales", 80, "4 foot tail", "rounded snout"];  alligator.indexOf("rounded snout"); // returns 3 

Como o método .includes(), o .indexOf() usa comparação estrita e não uma função como vimos com o método .find(). Mas, ao contrário do includes(), ele retorna o índice do elemento, em vez de um booleano. Você também pode indicar em qual índice do array iniciar a pesquisa.

Eu acho que indexOf() é muito útil. Ele é rápido e fácil, pode lhe dizer onde o elemento está no array e se o elemento existe. Como ele lhe diz se o elemento existe? Basicamente, podemos saber que o elemento existe se ele retorna um número positivo, e se ele retornar -1, sabemos que o elemento não existe.

alligator.indexOf("soft and fluffy"); // returns -1 alligator.indexOf(80); // returns 1 alligator.indexOf(80, 2); // returns -1 

E como você pode ver, embora pudéssemos usar os métodos find() ou findIndex() para nos dar a mesma informação, isso é muito menos para escrever. Não precisamos escrever uma função para comparação, pois ela já está dentro do método indexOf.

Agora, assim como os outros, indexOf() também retorna o índice do primeiro elemento de correspondência que ele encontra. O JavaScript nos dá um método de array alternativo .lastIndexOf(). Como você pode imaginar, isso faz a mesma coisa que indexOf(), mas a partir do último índice do array e trabalhando para trás. Você também pode especificar um segundo parâmetro, mas lembre-se que os índices não alteram, só porque você está usando um método diferente.

const alligator = ["thick scales", 80, "4 foot tail", "rounded snout", 80];  alligator.indexOf(80); // returns 1 alligator.lastIndexOf(80); // returns 4 alligator.indexOf(80, 2); // returns 4 alligator.lastIndexOf(80, 4); // returns 4 alligator.lastIndexOf(80, 3); // returns 1 

Bônus: filter

const alligator = ["thick scales", 80, "4 foot tail", "rounded snout", 80];  alligator.filter(el => el === 80); //returns [80, 80] 

O método filter() é como o método find(), na medida em que ele requer uma função passada e uma condição para o que será retornado. A diferença principal é que, filter() retorna sempre um array, mesmo que haja apenas um elemento correspondente. Mas ele irá retornar todos os elementos correspondentes, enquanto que find() retorna apenas a primeira correspondência.

O importante com o filtro é que ele retorna todos os elementos que correspondem aos seus critérios. Só poderia ser eu, mas posso ficar confuso, pensando “esses são os elementos que quero filtrar out”, quando sinceramente, você está indicando os elementos que você deseja filtrar in.

Conclusão

O método mais fácil que acho para usar ao pesquisar por algo é o método find(), mas como você pode ver, depende realmente do seu caso.

  • Você precisa saber apenas se ele existe? Use .includes().
  • Você precisa obter o elemento em si? Use .find(), ou .filter() para vários itens.
  • Você precisa encontrar o índice do elemento? Use .indexOf() ou findIndex() para uma pesquisa mais complexa.

Os arrays nos exemplos aqui foram muito simples. Você pode encontrar-se com um array de objetos. Aqui abaixo estão alguns exemplos básicos para navegar pela selva de objetos aninhados:

const jungle = [   { name: "frog", threat: 0 },   { name: "monkey", threat: 5 },   { name: "gorilla", threat: 8 },   { name: "lion", threat: 10 } ];  // break the object down in order to use .includes() or .indexOf() const names = jungle.map(el => el.name); // returns ['frog', 'monkey', 'gorilla', 'lion'] console.log(names.includes("gorilla")); // returns true console.log(names.indexOf("lion")); // returns 3 - which corresponds correctly assuming no sorting was done  // methods we can do on the array of objects console.log(jungle.find(el => el.threat == 5)); // returns object - {name: "monkey", threat: 5} console.log(jungle.filter(el => el.threat > 5)); // returns array - [{name: "gorilla", threat: 8}, {name: 'lion', threat: 10}]