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

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.

Rodolfo Mori7 min de leitura

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.

js
const quantidades = [10, 9, 1, 2, 100, 25];

console.log(quantidades.sort());
[ 1, 10, 100, 2, 25, 9 ]

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.

js
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));
-249.99999999999997 249.99999999999997 0

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:

js
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);
[ 39.9, 149.9, 289.9, 1199 ] [ 39.9, 149.9, 289.9, 1199 ] true

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:

js
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);
[ 39.9, 149.9, 289.9, 1199 ] [ 289.9, 149.9, 1199, 39.9 ] false

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:

js
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));
[ 39.9, 149.9, 289.9, 1199, 1899.9 ] [ 1899.9, 1199, 289.9, 149.9, 39.9 ]

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:

js
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')));
[ 'Bateria', 'Cadeira', 'Zíper', 'acessório', 'Áudio', 'Óculos' ] [ 'acessório', 'Áudio', 'Bateria', 'Cadeira', 'Óculos', 'Zíper' ]

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:

js
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));
[ 'Mouse sem fio: 149.9', 'Teclado mecânico: 289.9', 'Cadeira gamer: 1199', 'Monitor 27 polegadas: 1899.9' ] [ 'Cadeira gamer', 'Monitor 27 polegadas', 'Mouse sem fio', 'Teclado mecânico' ]

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.

js
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})`));
[ '87 un — Mouse sem fio (R$ 149.9)', '41 un — Teclado mecânico (R$ 289.9)', '41 un — Monitor 27 polegadas (R$ 1899.9)', '12 un — Cadeira gamer (R$ 1199)' ]

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:

js
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}`),
);
[ '2026-02-03', '2026-05-02', '2026-05-14' ] [ '1043 2026-05-14', '1044 2026-05-02', '1041 2026-02-03' ]

Erros comuns

O primeiro é silencioso: um comparador que devolve true/false em vez de número.

js
const precos = [1899.9, 39.9, 289.9, 149.9, 1199];

console.log(precos.toSorted((a, b) => a > b));
[ 1899.9, 39.9, 289.9, 149.9, 1199 ]

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.

js
const produtos = [
  { nome: 'Teclado mecânico', preco: 289.9 },
  { nome: 'Mouse sem fio', preco: 149.9 },
];

produtos.sort('preco');
file:///private/tmp/loja/arrays/ordenar-erro.mjs:6 produtos.sort('preco'); ^ TypeError: The comparison function must be either a function or undefined: preco at Array.sort (<anonymous>) at file:///private/tmp/loja/arrays/ordenar-erro.mjs:6:10 Node.js v24.16.0

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:

js
const tabelaDeFrete = Object.freeze([27.4, 12.5, 34.9, 18.9]);

tabelaDeFrete.sort((a, b) => a - b);
file:///private/tmp/loja/arrays/ordenar-congelado.mjs:3 tabelaDeFrete.sort((a, b) => a - b); ^ TypeError: Cannot assign to read only property '0' of object '[object Array]' at Array.sort (<anonymous>) at file:///private/tmp/loja/arrays/ordenar-congelado.mjs:3:15 Node.js v24.16.0

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.

js
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));
[ 3, 4, 4.5, 5, undefined, undefined ] [ 3, 4, 4.5, 5 ]

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.

  • arrays
  • sort
  • tosorted
  • localecompare
  • ordenacao

Perguntas frequentes

Por que sort() coloca 10 antes de 2?
Porque sem comparador o sort converte cada elemento para string e compara caractere por caractere, em ordem de código Unicode. Como "1" vem antes de "2", a string "10" vem antes de "2". Não é bug: é o comportamento especificado, e ele existe desde antes de o JavaScript ter tipos numéricos confiáveis em ordenação.
Qual a diferença entre sort e toSorted?
sort reordena o array original e devolve esse mesmo array; toSorted devolve um array novo e deixa o original intacto. Em código de interface, onde a mesma lista costuma alimentar mais de um componente, toSorted evita a classe de bug em que ordenar uma tabela muda a ordem em outra tela.
Preciso mesmo de localeCompare para ordenar nomes em português?
Precisa se os dados têm acento ou mistura de maiúsculas e minúsculas, o que é a regra em nome de cliente e nome de produto. A comparação padrão é por código Unicode, e nela "Zíper" vem antes de "Áudio". Com localeCompare e a tag pt-BR, a ordem é a que o usuário espera ver.
O comparador precisa devolver exatamente -1, 0 ou 1?
Não. O que importa é o sinal: qualquer número negativo mantém a ordem, qualquer positivo inverte e zero considera empate. Por isso a subtração funciona direto, mesmo devolvendo valores quebrados como -249.99999999999997.

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.sort() — developer.mozilla.org
  2. MDN — String.prototype.localeCompare() — developer.mozilla.org
  3. ECMAScript 2026 Language Specification — Array.prototype.toSorted — tc39.es

Continue por aqui