Ordenar array em JavaScript com sort()
Por que sort() sem comparador devolve 1, 10, 2 e como corrigir com subtração, toSorted sem mutar o original e localeCompare para acentos em pt-BR.
Ordenar em JavaScript tem uma pegadinha logo na primeira linha: sort() sem
argumento nenhum não ordena números. Ele converte tudo para texto e ordena
como texto, o que coloca 10 antes de 2 e 100 antes de 25.
A resposta curta: para número, use sort((a, b) => a - b). Para texto em
português, use sort((a, b) => a.localeCompare(b, 'pt-BR')). E, quase sempre,
prefira toSorted no lugar de sort — porque sort mexe no array original.
Os exemplos são de um painel de vendas: preços, quantidades vendidas e nomes de categoria de uma loja de periféricos.
O organizador lê etiquetas, não números
Imagine um funcionário colocando caixas em ordem pela etiqueta impressa. Para
ele, “10” vem antes de “2”, porque compara o primeiro caractere e para ali. É
exatamente a surpresa do sort() sem comparador: os valores são tratados como
texto para decidir a ordem.
O comparador é a instrução que muda esse critério. Quando ele devolve um
número negativo, zero ou positivo, informa qual item vem antes. Na primeira
microprática, escreva no papel a ordem textual e a ordem numérica da mesma
lista; as duas saídas mostram por que sort((a, b) => a - b) não é detalhe.
const quantidades = [10, 9, 1, 2, 100, 25];
console.log(quantidades.sort());Ninguém digitou nada errado. O sort transformou cada número em string e
comparou caractere por caractere: '1' vem antes de '2', então '10' e
'100' vêm antes de '2'. O resultado é uma ordem alfabética de números, que
não serve para nada — e que passa despercebida quando o array tem só um dígito
em cada posição.
O comparador é uma função que devolve número
Para ordenar de verdade, você entrega ao sort uma função que compara dois
elementos por vez. O que ela devolve não precisa ser -1, 0 ou 1: o sort
olha apenas o sinal.
const comparar = (a, b) => a - b;
console.log(comparar(39.9, 289.9));
console.log(comparar(289.9, 39.9));
console.log(comparar(149.9, 149.9));Negativo quer dizer “a vem antes de b”, positivo quer dizer “b vem
antes”, zero quer dizer empate. Por isso a subtração é o comparador universal
para números: ela produz o sinal certo sem esforço. Os decimais estranhos são o
ponto flutuante de sempre, e não atrapalham — o sort só quer saber se o
número é maior ou menor que zero.
sort muta o array original
Esta é a característica que mais causa dano em código de interface:
const precosOriginais = [289.9, 149.9, 1199, 39.9];
const ordenados = precosOriginais.sort((a, b) => a - b);
console.log(ordenados);
console.log(precosOriginais);
console.log(ordenados === precosOriginais);Não existem dois arrays. ordenados e precosOriginais são o mesmo array, com
dois nomes. Quem chamar precosOriginais depois dessa linha recebe a lista
reordenada, mesmo que dependesse da ordem original — a ordem de chegada dos
pedidos, por exemplo.
Repare que precosOriginais foi declarado com const e mudou assim mesmo.
const protege o vínculo entre nome e valor, não o conteúdo, como mostra a
lição de variáveis em JavaScript.
toSorted: ordenar sem estragar a lista
toSorted recebe o mesmo comparador e devolve um array novo:
const precosOriginais = [289.9, 149.9, 1199, 39.9];
const ordenados = precosOriginais.toSorted((a, b) => a - b);
console.log(ordenados);
console.log(precosOriginais);
console.log(ordenados === precosOriginais);O original ficou de pé. Antes de toSorted existir, a receita era
[...precos].sort(...) — copiar e então ordenar a cópia. Continua válida, e é
o que você vai encontrar em código um pouco mais antigo.
Crescente e decrescente são o mesmo comparador com a ordem dos operandos trocada:
const precos = [289.9, 149.9, 1199, 39.9, 1899.9];
console.log(precos.toSorted((a, b) => a - b));
console.log(precos.toSorted((a, b) => b - a));Acentos e maiúsculas: localeCompare com pt-BR
A comparação padrão de texto também é por código Unicode, e em português isso produz uma lista que nenhum usuário reconhece:
const categorias = ['Áudio', 'Zíper', 'Cadeira', 'Óculos', 'acessório', 'Bateria'];
console.log(categorias.toSorted());
console.log(categorias.toSorted((a, b) => a.localeCompare(b, 'pt-BR')));Na primeira lista, todas as maiúsculas sem acento vêm antes de qualquer
minúscula, e as acentuadas ficam no fim — Áudio depois de Zíper.
localeCompare com a tag pt-BR aplica as regras de ordenação do idioma:
acessório antes de Áudio, Óculos no lugar do O.
Ordenar array de objetos
Com objetos, o comparador acessa o campo que interessa e o resto é igual:
const produtos = [
{ nome: 'Teclado mecânico', preco: 289.9, vendidos: 41 },
{ nome: 'Mouse sem fio', preco: 149.9, vendidos: 87 },
{ nome: 'Cadeira gamer', preco: 1199, vendidos: 12 },
{ nome: 'Monitor 27 polegadas', preco: 1899.9, vendidos: 41 },
];
const porPreco = produtos.toSorted((a, b) => a.preco - b.preco);
console.log(porPreco.map((p) => `${p.nome}: ${p.preco}`));
const porNome = produtos.toSorted((a, b) => a.nome.localeCompare(b.nome, 'pt-BR'));
console.log(porNome.map((p) => p.nome));Campo numérico pede subtração, campo de texto pede localeCompare. Misturar os
dois — usar subtração em string — devolve NaN a cada comparação, e NaN não
é negativo nem positivo: o array volta praticamente como entrou.
Dois critérios, com desempate
O operador || encadeia comparadores: se o primeiro devolver 0, o segundo
decide.
const produtos = [
{ nome: 'Teclado mecânico', preco: 289.9, vendidos: 41 },
{ nome: 'Mouse sem fio', preco: 149.9, vendidos: 87 },
{ nome: 'Cadeira gamer', preco: 1199, vendidos: 12 },
{ nome: 'Monitor 27 polegadas', preco: 1899.9, vendidos: 41 },
];
const ranking = produtos.toSorted(
(a, b) => b.vendidos - a.vendidos || a.preco - b.preco,
);
console.log(ranking.map((p) => `${p.vendidos} un — ${p.nome} (R$ ${p.preco})`));Teclado e monitor empataram em 41 unidades, e o preço desempatou a favor do
mais barato. Vale saber que o sort do JavaScript é estável desde o ES2019:
elementos que empatam mantêm a ordem relativa que tinham. Isso permite ordenar
em duas passadas — primeiro por preço, depois por vendas — em vez de escrever
um comparador com três ||.
Datas em texto ISO (2026-05-14) ordenam corretamente como string, porque o
formato é ano-mês-dia. Fora desse formato, converta antes:
const pedidos = [
{ id: 1043, data: '2026-05-14' },
{ id: 1041, data: '2026-02-03' },
{ id: 1044, data: '2026-05-02' },
];
console.log(pedidos.toSorted((a, b) => a.data.localeCompare(b.data)).map((p) => p.data));
console.log(
pedidos
.toSorted((a, b) => new Date(b.data) - new Date(a.data))
.map((p) => `${p.id} ${p.data}`),
);Erros comuns
O primeiro é silencioso: um comparador que devolve true/false em vez de
número.
const precos = [1899.9, 39.9, 289.9, 149.9, 1199];
console.log(precos.toSorted((a, b) => a > b));Nada aconteceu. true vira 1 e false vira 0 — e como 0 significa
empate, o comparador nunca diz “troque de lugar” na direção contrária. O array
sai exatamente como entrou, sem erro nenhum no console. Escreva a - b.
O segundo é barulhento, e portanto melhor: passar algo que não é função.
const produtos = [
{ nome: 'Teclado mecânico', preco: 289.9 },
{ nome: 'Mouse sem fio', preco: 149.9 },
];
produtos.sort('preco');sort não aceita o nome do campo, como acontece em algumas bibliotecas de
outras linguagens. Ele aceita uma função, e nada mais — o tipo de callback
que a lição de funções em JavaScript detalha.
O terceiro aparece quando você tenta ordenar uma tabela de configuração
protegida com Object.freeze:
const tabelaDeFrete = Object.freeze([27.4, 12.5, 34.9, 18.9]);
tabelaDeFrete.sort((a, b) => a - b);Como sort escreve nas posições do array, congelar a lista impede a
ordenação. toSorted funcionaria sem reclamar, porque ele escreve num array
novo.
Valores ausentes
undefined recebe tratamento especial: ele nunca chega ao comparador e é
sempre empurrado para o fim.
const avaliacoes = [4.5, undefined, 3, 5, undefined, 4];
console.log(avaliacoes.toSorted((a, b) => a - b));
console.log(avaliacoes.filter((n) => n !== undefined).toSorted((a, b) => a - b));null, ao contrário, entra na conta: null - 3 é -3, então um null no meio
de notas se comporta como zero e vai parar no começo da lista. Filtre antes de
ordenar quando a origem dos dados é uma API.
Antes de ordenar, três perguntas
Ordenação parece um detalhe até virar bug de relatório. Antes de escrever o comparador, responda: o campo é número, texto ou data? A lista pode ser reordenada no lugar, ou alguém depende da ordem atual? Existe empate possível, e nesse caso o que decide?
Com as três respostas, o comparador se escreve sozinho — e você para de descobrir a ordenação errada pelo print que o cliente manda no suporte.
A próxima lição da trilha de JavaScript junta busca e ordenação nas receitas de array de objetos. Se você chegou aqui procurando um item específico dentro da lista, o caminho é buscar elemento em array. O guia completo de JavaScript mostra a trilha inteira.
Perguntas frequentes
Por que sort() coloca 10 antes de 2?
Qual a diferença entre sort e toSorted?
Preciso mesmo de localeCompare para ordenar nomes em português?
O comparador precisa devolver exatamente -1, 0 ou 1?
Dúvidas e comentários
Travou em algum passo? Pergunte aqui — a equipe e outros alunos respondem.
Entrar para perguntarÉ o mesmo login gratuito dos cursos.
Nenhuma dúvida por aqui ainda — a primeira pode ser a sua.
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
- MDN — Array.prototype.sort() — developer.mozilla.org
- MDN — String.prototype.localeCompare() — developer.mozilla.org
- ECMAScript 2026 Language Specification — Array.prototype.toSorted — tc39.es


