Tudo ou pelo menos um.
Essa é a forma mais resumida de explicar o every e some em Javascript:
O método every ("todo" ou "toda" em inglês) responde se todos os itens de uma array atendem aos requisitos
Já o some ("algum" ou "alguma") diz se pelo menos algum item atende aos requisitos
Esse tipo de pergunta é respondida com "sim" ou "não". Ou na programação, true ou false.
Por exemplo, todos os itens da array abaixo estão acima de zero?
const numbers = [ 3, 7, -1, 7, 10 ];
const result = numbers.every(function(number) {
if (number > 0) {
return true;
} else {
return false;
}
});
console.log(result); // false
A resposta é false, ou "não", nem todos os números estão abaixo de zero. Se eu removesse o -1
, a resposta seria diferente.
Com o some, a lógica é muito parecida. Porém basta que um item atenda aos requisitos para o retorno ser true:
const numbers = [ 3, 7, -1, 7, 10 ];
const result = numbers.some(function(number) {
if (number > 0) {
return true;
} else {
return false;
}
});
console.log(result); // true
Nesse caso, quatro dos cinco números da array estão acima de zero, então a resposta é "sim, pelo menos um número está acima de zero".
Veja agora outros detalhes importantes sobre esses métodos.
Every e some em Javascript
Como já falei, esses métodos são muito parecidos.
Então de agora em diante, tudo que você ler se aplica a ambos. A única diferença entre eles já expliquei na introdução, e vou mostrar nos desafios também.
A estrutura desses métodos é receber uma função callback que executa a cada item da array:
const numbers = [ 3, 7, -1, 7, 10 ];
numbers.some(function(number) {
console.log(number);
});
/*
3
7
-1
7
10
*/
Eles devem "partir" de uma array, já que ela é dona desses métodos:
const numbers = [ 3, 7, -1, 7, 10 ];
numbers.some();
// Ou
numbers.every();
// Ou
[ 3, 7, -1, 7, 10 ].some();
// Ou
[ 3, 7, -1, 7, 10 ].every();
Ou seja: algo que represente uma array + o ponto + o nome do método.
Apesar de haver uma iteração, o every e o some podem não executar em todos os itens.
Every e some podem parar de executar no meio da array
E isso não é por preguiça.
Esses métodos não precisam executar em todos os itens da array. Dependendo dos primeiros resultados, a resposta final não mudará.
Acompanhe esse raciocínio do every:
Já que o every responde se todos os itens da array atendem aos requisitos, se qualquer item não atender, a resposta final já será
false
. Mesmo que todos os outros sejamtrue
.
const numbers = [ 2, -3, 4, 5, 6 ];
const result = numbers.every(function(number) {
console.log('O número atual é: ', number);
if (number > 0) {
return true;
} else {
return false;
}
});
console.log('O resultado é: ', result);
Esse código mostra no console o número atual a cada iteração. E no final exibe o resultado:
O número atual é: 2
O número atual é: -3
O resultado é: false
Na primeira iteração, number
é 2, e tudo bem, já que ele está acima de zero. Porém na segunda iteração (-3), o próximo console já é o resultado final, ou seja, ele não iterou pelos números 4, 5 e 6.
Isso acontece porque, mesmo que todos os outros itens retornem true
, já se sabe que nem todos os itens atendem aos requisitos.
Isso acontece porque, mesmo que os próximos itens retornem true
, nem todos atendem aos requisitos.
Com o some acontece a mesma coisa:
Já que ele verifica se pelo menos um item da array atende aos requisitos, caso ele encontre um que não atende, não tem porquê continuar a execução.
A array de exemplo abaixo é um pouco diferente mas a lógica do teste com os consoles é a mesma:
const numbers = [ 2, 3, 4, -5, 6 ];
const result = numbers.some(function(number) {
console.log('O número atual é: ', number);
if (number < 0) {
return true;
} else {
return false;
}
});
console.log('O resultado é: ', result);
O resultado final será:
O número atual é: 2
O número atual é: 3
O número atual é: 4
O número atual é: -5
O resultado é: true
Quando o some encontra o primeiro número abaixo de zero (o critério), ele finaliza, já que pelo menos um item atende aos requisitos. É por isso que após o console do -5, vem o resultado, porque o some não iterou no último número, o 6.
Acho que já ficou claro para você, mas o retorno da função callback de every e some é bem importante.
O retorno da função callback de every e some
O retorno sempre é um booleano.
Isso acontece porque e cada iteração, é preciso dizer se o item atende ou não aos requisitos. E isso sempre acontece com um true
ou false
.
E se eu retornar algo que não é um booleano?
const numbers = [ -1, 0, 1 ];
const result = numbers.every(function(number) {
return number;
});
console.log(result); // false
Eu retornei o próprio number
, e o resultado final foi false
. Por quê?!
Quando o retorno não é um booleano explícito, o Javascript converte para poder prosseguir. Essa conversão se chama coerção de tipos.
Veja o que acontece com cada conversão:
const numbers = [ -1, 0, 1 ];
const result = numbers.every(function(number) {
console.log(number + ' é ' + Boolean(number));
return number;
});
console.log('O resultado é: ', result);
Adicionei um novo console dentro da função callback para mostrar como fica cada número após a conversão. E olha no que deu:
-1 é true
0 é false
O resultado é: false
O ponto principal é: qualquer número que não seja zero, quando você converte para booleano, vira true
. Assim que o every encontrou o zero, ele retornou false
e parou a execução.
O mesmo acontece com o some:
const numbers = [ -1, 0, 1 ];
const result = numbers.some(function(number) {
console.log(number + ' é ' + Boolean(number));
return number;
});
console.log('O resultado é: ', result);
/*
-1 é true
O resultado é: true
*/
Quando o some encontra o -1
, que é true
após a conversão, ele já finaliza.
Então nunca esqueça: o retorno da função callback de every e some sempre é um booleano.
Em todos os exemplos que dei, a função callback recebeu apenas o número como parâmetro. Mas é possível deixar a brincadeira mais interessante.
Os parâmetros da função callback de every e some
A função callback pode receber até 3 parâmetros:
Item
Index
Array
A partir de agora vou explicar cada um e propor um desafio para fixar bem o conteúdo.
Para isso, vou usar a array abaixo como base para os desafios (a área está em mil km²):
const maioresCidadesBrasil = [
{ nome: 'São Paulo', estado: 'SP', area: 1521, fusoHorario: 'UTC-3', clubesFutebol: [ 'Corinthians', 'Palmeiras', 'São Paulo', 'Santos' ] },
{ nome: 'Rio de Janeiro', estado: 'RJ', area: 1200, fusoHorario: 'UTC-3', clubesFutebol: [ 'Flamengo', 'Fluminense', 'Vasco', 'Botafogo' ] },
{ nome: 'Brasília', estado: 'DF', area: 5800, fusoHorario: 'UTC-3', clubesFutebol: [ 'Brasiliense', 'Gama' ] },
{ nome: 'Salvador', estado: 'BA', area: 706, fusoHorario: 'UTC-3', clubesFutebol: [ 'Bahia', 'Vitória' ] },
{ nome: 'Fortaleza', estado: 'CE', area: 314, fusoHorario: 'UTC-3', clubesFutebol: [ 'Ceará', 'Fortaleza' ] },
{ nome: 'Belo Horizonte', estado: 'MG', area: 331, fusoHorario: 'UTC-3', clubesFutebol: [ 'Atlético Mineiro', 'Cruzeiro' ] },
{ nome: 'Manaus', estado: 'AM', area: 11400, fusoHorario: 'UTC-4', clubesFutebol: [ 'Fast Clube' ] },
{ nome: 'Curitiba', estado: 'PR', area: 435, fusoHorario: 'UTC-3', clubesFutebol: [ 'Atlético Paranaense', 'Coritiba' ] },
{ nome: 'Recife', estado: 'PE', area: 218, fusoHorario: 'UTC-3', clubesFutebol: [ 'Náutico', 'Sport' ] },
{ nome: 'Porto Alegre', estado: 'RS', area: 496, fusoHorario: 'UTC-3', clubesFutebol: [ 'Grêmio', 'Internacional' ] }
];
Veja agora cada um dos parâmetros.
Primeiro parâmetro: item
O primeiro parâmetro você já conhece.
É o único obrigatório e usei ele em todos os exemplos até agora. Então resolva esse desafio: todas as 10 maiores cidades do Brasil têm uma área acima de 300 mil km²?
Aqui, basta verificar a propriedade .area
:
const result = maioresCidadesBrasil.every(function(cidade) {
if (cidade.area > 300) {
return true;
} else {
return false;
}
});
console.log(result); // false
O resultado é false
, porque nem todas as cidades possuem área acima de 300 mil km². Recife quebra esse padrão por ter apenas 218 mil km². Agora, se eu alterar o critério para 200 mil Km², o resultado muda:
const result = maioresCidadesBrasil.every(function(cidade) {
if (cidade.area > 200) {
return true;
} else {
return false;
}
});
console.log(result); // true
Agora um desafio para resolver com o some: entre as 10 maiores cidades do Brasil, existe alguma da Bahia (BA)?
O interessante desse tipo de teste é que você pode bater o olho na array e descobrir a resposta final. E depois que aplicar o código, fará a prova real (até rimou). Acredito que é muito produtivo aprender assim:
const result = maioresCidadesBrasil.some(function(cidade) {
if (cidade.estado === 'BA') {
return true;
} else {
return false;
}
});
console.log(result); // true
Aqui apenas verifico se a propriedade .estado
das cidades é igual ao estado da Bahia. Como existe pelo menos um item na array que atende ao requisito, o resultado final é true
.
Os desafios foram fáceis? Legal, veja agora o próximo parâmetro.
Segundo parâmetro: index
Ele é um número.
Na primeira iteração seu valor é zero, e a partir das próximas aumenta de 1 em 1.
maioresCidadesBrasil.some(function(cidade, index) {
console.log(index);
});
/*
0
1
2
3
4
5
6
7
8
9
*/
O último index é sempre igual à quantidade de itens da array menos 1. É por isso que o último index da array de cidades é 9, pois tem 10 itens.
Esse número é muito útil para várias situações, como por exemplo resolver o próximo desafio: verifique se todas as cidades estão no fuso horário UTC-3
, com exceção do item na posição 6.
Quero deixar claro que esse desafio serve apenas para você entender o parâmetro index
. Dificilmente você encontrará isso em um projeto real.
Para começar o código, vou criar um if
que ignora o item 6 (cidade de Manaus, a única com fuso horário UTC-4). Quando ele vier, retorno true
para que ele não altere o resultado final:
const result = maioresCidadesBrasil.every(function(cidade, index) {
if (index === 6) {
return true;
}
});
O código ainda não está pronto, pois preciso lidar com todos os outros itens da array. E para isso vou adicionar um outro if
que verifica o fuso horário deles. Se for "UTC-3", retorno true
também. Por fim, deixo um return false
para todos os outros casos:
const result = maioresCidadesBrasil.every(function(cidade, index) {
if (index === 6) {
return true;
}
if (cidade.fusoHorario === 'UTC-3') {
return true;
}
return false;
});
console.log(result); // true
O resultado final é true
, já que, com exceção de Manaus, todas as outras cidades estão no fuso horário UTC-3. Se você fizer o teste de remover o primeiro if
, verá que o resultado final muda para false
.
Agora um desafio com o some: descubra se a array tem pelo menos uma cidade que tem apenas um clube de futebol na propriedade clubesFutebol
, com exceção do index 6.
O código começa bem parecido com o anterior:
maioresCidadesBrasil.some(function(cidade, index) {
if (index === 6) {
return false;
}
});
Eu verifico se o index é 6, e nesse caso retorno false
e não true
. Isso porque, caso eu retornasse true
, eu não responderia à pergunta do desafio e sim outra pergunta. Que seria a array de cidade tem algum item no índice 6? ou a array de cidades tem pelo menos 7 itens?. E é mais simples responder essas perguntas de outras formas.
Se o index não for 6, então adiciono outro if
para verificar quantos times tem a array clubesFutebol
. Se for 1, retorno true
significa que achei minha resposta e o some finaliza a execução. Ao final deixo um return false
para deixar claro que acontece, mas ele é opcional:
const result = maioresCidadesBrasil.some(function(cidade, index) {
if (index === 6) {
return false;
}
if (cidade.clubesFutebol.length === 1) {
return true;
}
return false;
});
console.log(result); // false
A resposta final é false
, porque, com exceção do item no índice 6, todos os outros tem mais de 1 clube na array clubesFutebol
. Assim como no exemplo anterior, se você remover o primeiro if
, verá que o resultado muda para true
. Justamente pela cidade de Manaus que tem apenas o Fast Clube na array.
O index também é importante para outras operações, como descobrir se o item está em uma posição par ou impar na array. Expliquei isso nesse post sobre o método map em Javascript.
Veja agora o último parâmetro da função callback.
Terceiro parâmetro: array
Esse é o único parâmetro que não muda.
Ao longo das iterações, seu valor sempre é a array que você está iterando:
maioresCidadesBrasil.some(function(cidade, index, array) {
console.log(array) // maioresCidadesBrasil: [ ... ]
});
O código acima escreve no console a array maioresCidadesBrasil
a cada iteração. É importante você usar esse parâmetro apenas como consulta para outras operações, e nunca para mudar a array.
Esse último desafio farei apenas com o some: a array possui duas cidades no mesmo estado?
Por favor, muita atenção, isso aqui é muito importante. Num primeiro momento, parece que o some não pode resolver o desafio. Mas é seu trabalho como pessoa programadora transpor o problema de negócio (nesse caso, o desafio) para o código.
Então você pode ler a frase do desafio de outra forma: existe pelo menos uma cidade que tenha o valor da propriedade estado
igual a de outra cidade?
Agora que eu coloquei o trecho pelo menos no meio do desafio, ficou mais claro?
Começo o código com a variável quantidade
. Ela irá contar quantas cidades fazem parte do mesmo estado da cidade da iteração atual. E isso acontece a cada iteração:
maioresCidadesBrasil.some(function(cidade, index, array) {
let quantidade = 0;
});
Criei a variável quantidade
que vai contar isso para mim. Agora, dentro da função callback vou fazer um for
no parâmetro array
. Dentro do for
, se o estado for igual ao estado da cidade que estou iterando no every, adiciono 1 a essa variável:
maioresCidadesBrasil.some(function(cidade, index, array) {
let quantidade = 0;
for (i = 0; i < array.length; i++) {
if (array[i].estado === cidade.estado) {
quantidade = quantidade + 1;
}
}
console.log(quantidade); // 1
return true;
});
No final, eu coloquei um console na variável e um return true
, que serve apenas para o every iterar até o final. O console sempre vai me mostrar o valor 1, ou seja, existe apenas uma cidade para cada estado na array. Se você voltar no começo do post para conferir a array, verá que isso está certo.
Logo, é possível prever que o resultado final é false
, porque não há duas cidades no mesmo estado. Para confirmar isso vou adicionar o último if
no código:
const result = maioresCidadesBrasil.some(function(cidade, index, array) {
let quantidade = 0;
for (i = 0; i < array.length; i++) {
if (array[i].estado === cidade.estado) {
quantidade = quantidade + 1;
}
}
if (quantidade > 1) {
return true;
} else {
return false;
}
});
console.log(result); // false
Para você compreender melhor o que aconteceu, mude o estado de alguma cidade para outro já existente. Por exemplo, coloque a propriedade estado
de Porto Alegre para "PE"
. Você verá que o resultado final mudará para true
, porque agora sim a array possui duas cidades no mesmo estado.
Como já falei aqui no blog nos outros posts dessa série de métodos de array, não basta saber usar na teoria. É preciso entender o momento certo de aplicar cada um.
Como saber quando usar o every e some em Javascript?
Não é em every momento que esses métodos são úteis, mas isso acontece some vezes.
Para saber que é o momento de usar o every e some em Javascript, siga esses 2 passos.
Responder uma pergunta com "sim" ou "não"
Para começar, esses métodos são úteis em situações onde você precisa de um "sim" ou "não", verdadeiro ou falso, true
ou false
como resposta.
As perguntas seguem quase sempre esse modelo:
Every: "Todos os itens dessa lista atendem aos requisitos?"
Some: "Pelo menos um item dessa lista atende aos requisitos?"
Perceba que um simples "sim" ou "não" responde essas perguntas.
Isso é um ponto importante porque o retorno de every e some sempre é um booleano.
Você já tem uma array
Every e some são métodos de array, então você precisa de uma para começar.
Não é possível usá-los com string, number ou objeto, a não ser que você os converta em array antes.
Callback
Every e some são métodos de array em Javascript muito importantes.
Eles respondem perguntas com "sim" ou "não", ou true
ou false
.
O every responde se todos os itens de uma array atendem aos requisitos da função callback. Já o some diz se pelo menos um item da array atende aos requisitos.
Eles podem não iterar até o fim da array. Isso porque a resposta pode chegar antes. Se o every encontrar pelo menos 1 false
, a resposta final é false
. Da mesma forma, se o some encontrar pelo menos 1 true
, a resposta final será true
.
O retorno da função callback sempre será um valor booleano. Se o valor que você retornou não for um, o Javascript fará a coerção de tipo para garantir isso.
A função callback tem 3 parâmetros. O item de cada iteração, seu índice e a própria array que você está iterando.
Para saber o momento de usar every e some, preste atenção nesses dois requisitos. Primeiro, eles funcionam em situações onde você precisa responder uma pergunta com "sim" ou "não". E por último, você tem uma array para realizar essa operação.
De todos os artigos sobre métodos de array, esse foi um dos mais legais e mais trabalhosos. Porque foi o único com dois métodos no mesmo texto.
Se você perdeu os outros, veja aqui:
Como usar o forEach em Javascript: exemplos detalhados contados em uma história
Transforme arrays em ouro: aprenda a manipular dados com o map() em Javascript
Domine o método Filter e simplifique sua lógica com arrays em Javascript
Além desse, ainda sairá o último artigo sobre o método reduce. Então aguarde só mais uns dias :)
Obrigado pela sua leitura.
Ficou com alguma dúvida? Comente abaixo que será um prazer responder.
Se esse artigo te ajudou de alguma forma, e você sentiu vontade de dizer um obrigado, compartilhe com um amigo ou nas suas redes sociais.
Até mais.