Pular para o conteúdo
Cursos

DevClub

LógicaFront-endBack-endMobile

IA Club

IA na prática
Estudar programaçãoEstudar IA
LiçãoIniciantecódigo testado

Buscar elemento em array: find, includes e indexOf

find devolve o elemento, findIndex o índice e filter um array. Veja também por que indexOf não acha objeto igual nem NaN, com saída real no Node.

Rodolfo Mori6 min de leitura

Buscar em um array começa pela pergunta que você quer responder: “qual é o produto?”, “em que posição ele está?”, “existe algum?” ou “quais atendem à condição?”. O JavaScript oferece métodos diferentes porque cada pergunta pede um tipo de resposta diferente.

Imagine pedir ajuda numa biblioteca. find entrega o primeiro livro que atende ao pedido; findIndex informa a posição dele na estante; some responde apenas sim ou não; filter monta uma pilha com todos os resultados. No array, o bibliotecário é a função de teste executada para cada item. O método pode parar no primeiro acerto ou percorrer a lista inteira, conforme a resposta prometida.

Em termos técnicos, find devolve o elemento, findIndex devolve o índice, filter devolve um novo array, includes devolve um booleano e indexOf devolve a posição de um valor simples. Quando nada aparece, um método de elemento devolve undefined; um método de posição devolve -1.

Os exemplos usam o catálogo de uma loja de periféricos, o mesmo domínio de variáveis em JavaScript.

find devolve o elemento, não o índice

find recebe uma função que responde sim ou não para cada item e devolve o primeiro item que responde sim.

js
const produtos = [
  { sku: 'TEC-001', nome: 'Teclado mecânico', preco: 289.9, estoque: 12 },
  { sku: 'MOU-014', nome: 'Mouse sem fio', preco: 149.9, estoque: 0 },
  { sku: 'CAD-220', nome: 'Cadeira gamer', preco: 1199, estoque: 3 },
];

const achado = produtos.find((p) => p.sku === 'CAD-220');

console.log(achado);
console.log(achado.nome, achado.preco);
{ sku: 'CAD-220', nome: 'Cadeira gamer', preco: 1199, estoque: 3 } Cadeira gamer 1199

O objeto que saiu do find é o mesmo objeto que está no array, não uma cópia. Alterar achado.estoque altera o array. Isso é conveniente quando você quer editar o item e incômodo quando você achava que estava trabalhando com uma cópia.

Trocando o método, a mesma condição responde outra coisa:

js
const produtos = [
  { sku: 'TEC-001', nome: 'Teclado mecânico', categoria: 'periferico' },
  { sku: 'MOU-014', nome: 'Mouse sem fio', categoria: 'periferico' },
  { sku: 'CAD-220', nome: 'Cadeira gamer', categoria: 'movel' },
];

const ehPeriferico = (p) => p.categoria === 'periferico';

console.log(produtos.find(ehPeriferico));
console.log(produtos.findIndex(ehPeriferico));
console.log(produtos.filter(ehPeriferico));
{ sku: 'TEC-001', nome: 'Teclado mecânico', categoria: 'periferico' } 0 [ { sku: 'TEC-001', nome: 'Teclado mecânico', categoria: 'periferico' }, { sku: 'MOU-014', nome: 'Mouse sem fio', categoria: 'periferico' } ]

Mesma função de teste, três respostas: um objeto, um número e um array. A função que você passa é um callback comum, do tipo que a lição de funções em JavaScript mostra em detalhe.

Quando nada é encontrado

Aqui está a diferença que decide como você escreve a próxima linha:

js
const produtos = [
  { sku: 'TEC-001', nome: 'Teclado mecânico' },
  { sku: 'MOU-014', nome: 'Mouse sem fio' },
];

console.log(produtos.find((p) => p.sku === 'MON-007'));
console.log(produtos.findIndex((p) => p.sku === 'MON-007'));
console.log(produtos.filter((p) => p.sku === 'MON-007'));
undefined -1 []

Três formas diferentes de dizer “não achei”. A do find é a perigosa: um undefined que segue viajando pelo programa até alguém tentar ler uma propriedade dele. O -1 do findIndex também engana, porque é um número válido e if (indice) considera -1 verdadeiro. Sempre compare com !== -1, nunca teste a verdade do índice.

includes e indexOf são para valores simples

Quando o array guarda strings ou números, você não precisa de callback nenhum:

js
const cuponsAtivos = ['PRIMEIRACOMPRA', 'FRETEGRATIS', 'BLACKFRIDAY'];

console.log(cuponsAtivos.includes('FRETEGRATIS'));
console.log(cuponsAtivos.indexOf('FRETEGRATIS'));
console.log(cuponsAtivos.indexOf('NATAL10'));
console.log(cuponsAtivos.includes('fretegratis'));
true 1 -1 false

A última linha é o bug mais comum com cupom: a comparação é sensível a maiúsculas. Normalize com .trim().toUpperCase() antes de comparar o que veio do formulário.

Os dois aceitam uma posição inicial como segundo argumento, e existe ainda o lastIndexOf, que procura do fim para o começo:

js
const skusDoCarrinho = ['TEC-001', 'MOU-014', 'TEC-001'];

console.log(skusDoCarrinho.indexOf('TEC-001'));
console.log(skusDoCarrinho.lastIndexOf('TEC-001'));
console.log(skusDoCarrinho.indexOf('TEC-001', 1));
console.log(skusDoCarrinho.includes('TEC-001', 2));
0 2 2 true

Objeto igual não é o mesmo objeto

Esta é a armadilha que mais consome tempo de quem está começando. includes e indexOf comparam com igualdade estrita — e dois objetos com exatamente o mesmo conteúdo não são iguais em JavaScript.

js
const carrinho = [{ sku: 'TEC-001', quantidade: 1 }];

console.log(carrinho.includes({ sku: 'TEC-001', quantidade: 1 }));
console.log(carrinho.indexOf({ sku: 'TEC-001', quantidade: 1 }));

const mesmoItem = carrinho[0];
console.log(carrinho.includes(mesmoItem));
console.log(carrinho.some((item) => item.sku === 'TEC-001'));
false -1 true true

As duas primeiras linhas falharam porque o objeto escrito dentro do includes é um objeto novo, criado naquele instante, que por acaso tem o mesmo conteúdo. A terceira funcionou porque mesmoItem é literalmente a mesma referência guardada no array.

O caso NaN

Existe exatamente um valor em que includes e indexOf discordam, e ele aparece sempre que uma conversão de número dá errado — nota de avaliação vinda de um campo de texto, preço lido de uma planilha:

js
const notas = [4.5, 5, Number('quatro'), 3];

console.log(notas);
console.log(notas.indexOf(NaN));
console.log(notas.includes(NaN));
console.log(notas.findIndex(Number.isNaN));
[ 4.5, 5, NaN, 3 ] -1 true 2

indexOf usa ===, e NaN === NaN é false — regra do padrão de ponto flutuante, não capricho da linguagem. includes usa outro algoritmo de comparação, o SameValueZero, em que NaN é igual a si mesmo. Se você precisa da posição, findIndex(Number.isNaN) resolve.

some e every: existe algum? valem todos?

Quando a pergunta é sim ou não sobre a coleção inteira, esses dois dizem a intenção melhor do que qualquer laço:

js
const itens = [
  { sku: 'TEC-001', estoque: 12 },
  { sku: 'MOU-014', estoque: 0 },
  { sku: 'CAD-220', estoque: 3 },
];

console.log(itens.some((i) => i.estoque === 0));
console.log(itens.every((i) => i.estoque > 0));

const carrinhoVazio = [];
console.log(carrinhoVazio.every((i) => i.estoque > 0));
console.log(carrinhoVazio.some((i) => i.estoque > 0));
true false true false

Repare na terceira linha. every de um array vazio é true. Não é bug: a afirmação “todos os itens têm estoque” é verdadeira quando não existe item nenhum que a contrarie — é o chamado verdadeiro vacuoso. Na prática isso vira um pedido vazio passando pela validação de estoque e seguindo para o pagamento. Se o carrinho vazio não pode passar, teste o tamanho antes: itens.length > 0 && itens.every(...).

Buscar do fim para o começo

findLast e findLastIndex fazem o mesmo trabalho do find, varrendo na ordem inversa. É o que você quer quando a lista está em ordem cronológica e interessa o evento mais recente:

js
const pedidos = [
  { id: 1041, cliente: 'Ana', status: 'pago' },
  { id: 1042, cliente: 'Bruno', status: 'cancelado' },
  { id: 1043, cliente: 'Ana', status: 'pago' },
  { id: 1044, cliente: 'Carla', status: 'aguardando' },
];

console.log(pedidos.find((p) => p.status === 'pago'));
console.log(pedidos.findLast((p) => p.status === 'pago'));
console.log(pedidos.findLastIndex((p) => p.status === 'pago'));
{ id: 1041, cliente: 'Ana', status: 'pago' } { id: 1043, cliente: 'Ana', status: 'pago' } 2

A alternativa antiga era inverter o array antes de procurar — o que copiava a lista inteira só para achar um item. Se a ordem em que os itens estão te importa, vale ler a lição de ordenar array com sort antes de confiar na sequência que veio da API.

Erros comuns: o find que não achou

Este é o erro número um de quem aprendeu find hoje. O código funciona com o SKU certo e explode com o SKU digitado errado:

js
const produtos = [
  { sku: 'TEC-001', nome: 'Teclado mecânico', preco: 289.9 },
  { sku: 'MOU-014', nome: 'Mouse sem fio', preco: 149.9 },
];

const codigoDigitado = 'MOU-15';
const produto = produtos.find((p) => p.sku === codigoDigitado);

console.log(`Produto: ${produto.nome}`);
file:///private/tmp/loja/arrays/busca-erro.mjs:9 console.log(`Produto: ${produto.nome}`); ^ TypeError: Cannot read properties of undefined (reading 'nome') at file:///private/tmp/loja/arrays/busca-erro.mjs:9:33 Node.js v24.16.0

O erro não está na linha 9: está na linha 7, onde o find devolveu undefined e ninguém conferiu. A mensagem Cannot read properties of undefined sempre aponta para o uso, nunca para a origem — o diagnóstico completo está em TypeError: Cannot read properties of undefined.

A correção tem duas metades: uma guarda explícita quando o programa precisa reagir à ausência, e ?. com ?? quando um valor de reserva basta.

js
const produtos = [
  { sku: 'TEC-001', nome: 'Teclado mecânico', preco: 289.9 },
  { sku: 'MOU-014', nome: 'Mouse sem fio', preco: 149.9 },
];

function descrever(codigo) {
  const produto = produtos.find((p) => p.sku === codigo);
  if (!produto) return `SKU ${codigo} não está no catálogo`;
  return `${produto.nome} — R$ ${produto.preco.toFixed(2)}`;
}

console.log(descrever('TEC-001'));
console.log(descrever('MOU-15'));

const talvez = produtos.find((p) => p.sku === 'MOU-15');
console.log(talvez?.nome ?? 'sem nome');
Teclado mecânico — R$ 289.90 SKU MOU-15 não está no catálogo sem nome

Qual usar em cada caso

pergunta método devolve quando acha devolve quando não acha
qual é o item? find o elemento undefined
em que posição está? findIndex o índice -1
quais são todos? filter array com os itens []
existe algum? some true false
valem todos? every true false (e true se vazio)
esse valor simples está aí? includes true false
em que posição está esse valor? indexOf o índice -1

Três hábitos que evitam a maior parte dos problemas: escolha pelo que você vai fazer com a resposta, não pelo método que lembrou primeiro; nunca encadeie um acesso a propriedade logo depois de um find; e para array de objetos prefira some a includes, sempre.

Agora transforme uma pergunta em código: com os produtos do artigo, descubra se existe algum item sem estoque, recupere o primeiro produto acima de R$ 500 e liste todos abaixo de R$ 300. Os tipos esperados são boolean, objeto ou undefined, e array. Imprima também um SKU inexistente para confirmar que sua guarda trata a ausência antes de acessar .nome.

A próxima lição da trilha de JavaScript trata de ordenar array com sort, e logo depois vêm as receitas completas de array de objetos — somar, agrupar e detectar duplicado. O guia completo de JavaScript mostra onde cada assunto entra na sequência.

  • arrays
  • find
  • includes
  • indexof
  • busca

Perguntas frequentes

Uso find ou filter quando sei que só existe um resultado?
Use find. Ele devolve o objeto direto, para de percorrer no primeiro acerto e deixa claro para quem lê o código que a resposta é uma só. Com filter você recebe um array e ainda precisa pegar a posição zero — e um array vazio não avisa que a busca falhou, ele só passa despercebido pelo resto do programa.
Posso usar includes para procurar um objeto dentro de um array?
Só se você tiver em mãos exatamente a mesma referência que está no array. includes e indexOf comparam com igualdade estrita, e dois objetos com o mesmo conteúdo são valores diferentes para o JavaScript. Para procurar por conteúdo, use some com uma comparação de campo, normalmente o id ou o SKU.
Por que indexOf não encontra NaN e includes encontra?
indexOf compara com ===, e NaN === NaN é false por definição do padrão de ponto flutuante. includes usa outro algoritmo de comparação, o SameValueZero, que trata NaN como igual a si mesmo. É a única diferença prática entre os dois, e ela só aparece com número quebrado vindo de conversão.
some e every percorrem o array inteiro?
Não. some para no primeiro elemento que satisfaz a condição e every para no primeiro que falha. Em lista grande isso importa, mas o motivo principal de usá-los é outro: o nome já diz a pergunta que você está fazendo, e quem lê não precisa decifrar um contador.

Dúvidas e comentários

Travou em algum passo? Pergunte aqui — a equipe e outros alunos respondem.

Todo o código deste artigo foi executado em Node 24.16.0, e as saídas exibidas são as reais — como produzimos este conteúdo.

Fontes consultadas

  1. MDN — Array.prototype.find() — developer.mozilla.org
  2. MDN — Array.prototype.includes() — developer.mozilla.org
  3. ECMAScript 2026 Language Specification — SameValueZero — tc39.es

Continue por aqui