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

Adicionar e remover elementos de um array em JS

push, pop, shift, unshift e splice mudam o array original mesmo declarado com const — e por que delete deixa buraco. Com toSpliced e with, do ES2023.

Rodolfo Mori7 min de leitura

Para adicionar ou remover itens de um array, primeiro decida duas coisas: em qual ponta você quer mexer e se o array original pode mudar. push e pop atuam no fim; unshift e shift, no começo; splice, em uma posição que você escolhe no meio.

Imagine uma fila escrita num quadro. push põe uma pessoa no fim, pop tira a última, unshift coloca alguém na frente e shift chama a primeira. splice permite apagar ou inserir a partir de uma posição específica. No JavaScript, o “quadro” é o próprio array: esses cinco métodos alteram a lista original. Eles não entregam uma cópia; devolvem o novo tamanho, o item removido ou a lista do que saiu, dependendo do método.

Isso vale mesmo quando o array foi declarado com const. const impede trocar a referência inteira, mas não congela os itens que estão dentro dela. Entender essa diferença evita uma classe de bugs que aparece em parâmetros, estado de componentes e objetos compartilhados.

Se você ainda não viu por que um array aceita mudar sendo const, a lição arrays em JavaScript mostra o que o array guarda por dentro. Aqui o assunto é o que você faz com ele.

push e pop: o fim do array

js
const carrinho = ['Teclado mecânico'];

const tamanho = carrinho.push('Mouse sem fio', 'Headset');
console.log(tamanho, carrinho);

const removido = carrinho.pop();
console.log(removido);
console.log(carrinho);
3 [ 'Teclado mecânico', 'Mouse sem fio', 'Headset' ] Headset [ 'Teclado mecânico', 'Mouse sem fio' ]

push aceita quantos argumentos você quiser e devolve o novo tamanho — não o array. Quem escreve const novo = lista.push(item) e depois trata novo como lista está guardando o número 3.

pop devolve o item que saiu. Em array vazio, devolve undefined sem reclamar.

shift e unshift: o começo do array

js
const fila = ['Pedido 1041', 'Pedido 1042', 'Pedido 1043'];

const proximo = fila.shift();
console.log(proximo);
console.log(fila);

fila.unshift('Pedido 1040 (urgente)');
console.log(fila);
console.log(fila.length);
Pedido 1041 [ 'Pedido 1042', 'Pedido 1043' ] [ 'Pedido 1040 (urgente)', 'Pedido 1042', 'Pedido 1043' ] 3

shift e unshift são o par simétrico de pop e push, do outro lado. A simetria acaba no custo: mexer no começo obriga o motor a renumerar todos os índices que vêm depois. Com uma fila de dez pedidos ninguém percebe; com cem mil itens dentro de um laço, percebe.

splice: cortar e inserir no meio

splice(inicio, quantosRemover, ...itensParaInserir). É o único dos cinco que faz as duas coisas de uma vez:

js
const carrinho = ['Teclado mecânico', 'Mouse sem fio', 'Headset', 'Webcam'];

const removidos = carrinho.splice(1, 2);
console.log(removidos);
console.log(carrinho);

carrinho.splice(1, 0, 'Monitor 27"', 'Suporte de monitor');
console.log(carrinho);

carrinho.splice(0, 1, 'Teclado sem fio');
console.log(carrinho);
[ 'Mouse sem fio', 'Headset' ] [ 'Teclado mecânico', 'Webcam' ] [ 'Teclado mecânico', 'Monitor 27"', 'Suporte de monitor', 'Webcam' ] [ 'Teclado sem fio', 'Monitor 27"', 'Suporte de monitor', 'Webcam' ]

Três usos numa sequência só. Com quantosRemover em 0, splice vira uma inserção pura. Com remoção e inserção juntas, vira substituição. E o valor de retorno é sempre a lista do que saiu — array vazio quando nada saiu.

splice não é slice

Os nomes diferem por uma letra e os efeitos são opostos. Um corta o original, o outro fotografa:

js
const catalogo = ['Teclado mecânico', 'Mouse sem fio', 'Headset', 'Webcam'];

const paginaUm = catalogo.slice(1, 3);
console.log(paginaUm);
console.log(catalogo);

const cortados = catalogo.splice(1, 2);
console.log(cortados);
console.log(catalogo);
[ 'Mouse sem fio', 'Headset' ] [ 'Teclado mecânico', 'Mouse sem fio', 'Headset', 'Webcam' ] [ 'Mouse sem fio', 'Headset' ] [ 'Teclado mecânico', 'Webcam' ]

As duas primeiras linhas: slice devolveu o pedaço e o catálogo continua com quatro itens. As duas últimas: splice devolveu o mesmo pedaço e o catálogo ficou com dois.

O retorno idêntico é o que torna a troca perigosa — você testa com o retorno, vê o valor certo e só descobre o estrago quando outra parte do código lê o catálogo. Vale também a diferença de assinatura: slice(inicio, fim) recebe duas posições; splice(inicio, quantidade) recebe posição e contagem.

método o que devolve altera o original 2º argumento
slice(i, f) pedaço novo não índice final (exclusivo)
splice(i, n) o que foi removido sim quantidade a remover
toSpliced(i, n) array novo já cortado não quantidade a remover

const não impede push — impede reatribuir

Aqui está a prova, no mesmo arquivo:

js
const carrinho = ['Teclado mecânico'];

carrinho.push('Mouse sem fio');
carrinho.splice(0, 1);
console.log(carrinho);

carrinho = ['Headset'];
[ 'Mouse sem fio' ] file:///private/tmp/loja/carrinho-const.mjs:7 carrinho = ['Headset']; ^ TypeError: Assignment to constant variable. at file:///private/tmp/loja/carrinho-const.mjs:7:10 at ModuleJob.run (node:internal/modules/esm/module_job:439:25) at async node:internal/modules/esm/loader:633:26 at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:101:5) Node.js v24.16.0

O push passou. O splice passou. O console.log imprimiu o array já modificado. Só a reatribuição quebrou.

const congela o vínculo entre o nome carrinho e aquele array específico. O conteúdo do array não é da conta dele. É por isso que praticamente todo array em código moderno é declarado com const — e continua mudando o dia inteiro. O mesmo mecanismo, com objetos, aparece em variáveis em JavaScript.

delete deixa buraco e não muda o length

delete funciona em objeto. Array é objeto. Logo, delete “funciona” em array — e é justamente aí que a lógica te trai:

js
const carrinho = ['Teclado mecânico', 'Mouse sem fio', 'Headset'];

delete carrinho[1];

console.log(carrinho);
console.log(carrinho.length);
console.log(carrinho[1]);
console.log(carrinho.filter(Boolean).length);
[ 'Teclado mecânico', <1 empty item>, 'Headset' ] 3 undefined 2

O item sumiu, o length continua 3 e a posição 1 virou um buraco — nem undefined de verdade, uma chave que deixou de existir. O carrinho agora mostra “3 itens” para o cliente e entrega dois. O filter(Boolean) no fim prova que só duas posições sobreviveram.

Regra sem exceção prática: delete não remove item de array. Use splice (quando quiser mutar) ou filter (quando quiser um array novo).

Sem mutar: toSpliced, with e toSorted

O ES2023 fechou o buraco mais irritante da API: até então, sort, reverse e splice só existiam na versão que estraga o original. Agora existe o par imutável de cada um:

js
const carrinho = ['Teclado mecânico', 'Mouse sem fio', 'Headset'];

const semMouse = carrinho.toSpliced(1, 1);
const trocado = carrinho.with(2, 'Headset Pro');
const ordenado = carrinho.toSorted();

console.log(semMouse);
console.log(trocado);
console.log(ordenado);
console.log(carrinho);
[ 'Teclado mecânico', 'Headset' ] [ 'Teclado mecânico', 'Mouse sem fio', 'Headset Pro' ] [ 'Headset', 'Mouse sem fio', 'Teclado mecânico' ] [ 'Teclado mecânico', 'Mouse sem fio', 'Headset' ]

Três operações e o carrinho da última linha continua exatamente como nasceu — inclusive na ordem, que o toSorted reorganizou só na cópia. Trocar essa linha por carrinho.sort() deixaria o original ordenado para sempre. with(indice, valor) é a versão imutável de lista[i] = valor — e resolve num método o que antes exigia espalhar e reatribuir.

Os pares completos são sort/toSorted, reverse/toReversed, splice/toSpliced e a atribuição por índice, que ganhou with. Em React, em Redux ou em qualquer estado que você compara por referência, é essa metade da tabela que você quer.

Remover pelo conteúdo, não pela posição

No mundo real você raramente sabe o índice. Você sabe o SKU:

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

function removerPorSku(itens, sku) {
  const posicao = itens.findIndex((item) => item.sku === sku);
  if (posicao === -1) return false;
  itens.splice(posicao, 1);
  return true;
}

console.log(removerPorSku(carrinho, 'MOU-014'));
console.log(removerPorSku(carrinho, 'NAO-EXISTE'));
console.log(carrinho.map((item) => item.sku));
true false [ 'TEC-001', 'HDS-007' ]

A linha que faz esta função ser segura é if (posicao === -1) return false. Sem ela, o código a seguir faria um estrago silencioso:

js
const carrinho = ['Teclado mecânico', 'Mouse sem fio', 'Headset'];

const posicao = carrinho.findIndex((item) => item === 'Webcam');
console.log(posicao);

carrinho.splice(posicao, 1);
console.log(carrinho);
-1 [ 'Teclado mecânico', 'Mouse sem fio' ]

O produto procurado nem estava no carrinho, e mesmo assim um item foi removido. Motivo: findIndex devolveu -1, e splice interpreta índice negativo como contagem a partir do fim — -1 é a última posição. Nenhum erro, nenhum aviso, o Headset sumiu.

Esse é o bug de array mais difícil de rastrear na produção, porque o sintoma aparece na tela do cliente e não no log. Sempre teste o -1.

Esvaziar o carrinho inteiro

js
const carrinho = ['Teclado mecânico', 'Mouse sem fio', 'Headset'];
const espelho = carrinho;

carrinho.length = 0;

console.log(carrinho);
console.log(espelho);
console.log(carrinho === espelho);
[] [] true

length = 0 esvazia no lugar: quem mais apontava para aquele array (aqui, espelho) enxerga o array vazio junto. carrinho = [] faria o contrário — criaria um array novo e deixaria espelho com os três itens antigos, o que costuma virar uma tela que não atualiza.

splice(0, carrinho.length) tem o mesmo efeito de length = 0 e ainda devolve o que saiu, se você precisar guardar.

Qual usar em cada situação

o que você quer método muta
acrescentar no fim push sim
tirar o último pop sim
tirar o primeiro shift sim
inserir no começo unshift sim
remover/inserir no meio splice sim
um pedaço, sem mexer slice não
remover por condição filter não
trocar um item por índice with não
esvaziar mantendo a referência length = 0 sim

O critério de escolha não é “mutar é feio”. É: alguém mais está olhando para este array? Array local, criado três linhas acima e usado ali mesmo, pode mutar à vontade — é mais rápido e mais direto. Array que veio por parâmetro, que é estado de componente ou que está guardado num objeto compartilhado, você não muta: devolve um novo.

Faça um teste de dois minutos: crie const fila = ['Ana', 'Beto', 'Caio'], guarde const copia = fila e execute fila.shift(). As duas variáveis devem mostrar ['Beto', 'Caio'], porque apontam para o mesmo array. Repita usando const novaFila = fila.slice(1) e confirme que o original não muda. Essa comparação torna visível a diferença entre mutar e criar uma nova lista.

A próxima lição da trilha de JavaScript é percorrer array em JavaScript, e ela começa justamente com a armadilha de remover item enquanto você percorre. Depois vem map, filter e reduce, o lado imutável desta mesma história. O guia completo de JavaScript mostra onde cada assunto entra.

  • arrays
  • push
  • splice
  • mutacao
  • imutabilidade

Perguntas frequentes

Se o array é const, por que push funciona?
Porque const trava o vínculo entre o nome e o valor, não o conteúdo do valor. push mexe por dentro do array e deixa a referência intacta; só reatribuir o nome, com carrinho = [], é que dispara o TypeError.
Quando usar splice e quando usar slice?
splice quando você quer alterar o array original e receber de volta o que saiu. slice quando você quer um pedaço novo e o original preservado — é o método certo para paginação e para copiar antes de mexer.
Por que não devo usar delete num array?
Porque delete apaga a chave e deixa o length no mesmo valor. Você fica com um buraco que map e forEach pulam, filter descarta e Array.from converte em undefined. Para tirar um item de verdade, use splice ou filter.
toSpliced é sempre melhor que splice?
Não. toSpliced devolve um array novo, o que é ótimo em React e em código funcional, mas custa uma cópia inteira a cada chamada. Num laço quente com muitos itens, splice no lugar continua sendo mais barato.

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.splice() — developer.mozilla.org
  2. MDN — Array.prototype.toSpliced() — developer.mozilla.org
  3. ECMAScript 2026 Language Specification — Properties of the Array Prototype Object — tc39.es

Continue por aqui