Dia 8 — Arrays

Informatica · Conteudo · publicado em 05/10/2026
Aula 1

Criar, ler e alterar um array

Criar, ler e alterar um array

Array é a lista. No React Native é a estrutura que carrega quase tudo que a

tela mostra: as tarefas, os itens de um carrinho, as mensagens de um chat. Tudo

que vem de API chega como array.

const tarefas = ['estudar', 'treinar'];
console.log(tarefas[0]);        // 'estudar'

Cada posição é um índice, e começa em zero. O índice do segundo item é 1.

O length é o número de itens:

console.log(tarefas.length);   // 2

O length não é só leitura: atribuir a ele corta o array. tarefas.length = 1

deixa só o primeiro item, e é a forma mais curta de esvaziar.

O exemplo abre com a lista de dois itens e imprime

indice 0: estudar | indice 1: treinar | length: 2. Os três dados da página

saem na mesma linha: o índice começa em zero, o segundo item é 1, e o

length é 2 — um a mais que o maior índice.

O corte pelo length aparece mais adiante, e a saída é length = 1 corta: [ 1 ].

Três itens viraram um, e o que sobrou foi o primeiro. Não há método para isso

porque o length é a propriedade que o array expõe para escrita — é o único

método de array que muda o array sem devolver nada.

Criar array de três jeitos

const a = [1, 2, 3];                       // literal, o mais comum
const b = new Array(3);                    // tres posicoes vazias
const c = Array.of(1, 2, 3);               // igual ao literal

O literal [] é o que se escreve. new Array(3) cria três posições vazias —

não o número 3 dentro, e é essa diferença que morde quem usa new Array por

engano. O array vazio é [], e Array.isArray([]) confirma que o valor é

array:

console.log(Array.isArray([]), Array.isArray('Ana'));

Para transformar outra coisa em array: Array.from('Ana') quebra a string em

letras, Array.from({ length: 3 }, (_, i) => i * 2) cria [0, 2, 4], e

[].concat(outro) junta dois arrays num terceiro.

As três conversões do exemplo estão em três linhas: `Array.from('Ana'): [ 'A',

'n', 'a' ], Array.from com funcao: [ 0, 2, 4 ] e concat: [ 1, 2, 3 ]`. A

segunda é a que mais aparece em app: o primeiro argumento { length: 3 } diz

quantos itens criar, e a função diz o valor de cada um — i * 2 produziu 0, 2

e 4. É a mesma forma do Array.from usado para gerar uma lista de teste sem

escrever os três valores à mão.

O concat começa com [] na frente, e o detalhe é que o array vazio é o

primeiro argumento: é ele que existe para receber o resultado. `[].concat([1, 2],

[3])` achata os dois arrays num só. Com um array no meio e outro depois, o

resultado seria [1, 2, 3, [4]] — o último não é achatado.

Acrescentar e remover

MétodoO que fazDevolve
push(item)acrescenta no fimnovo length
pop()remove do fimo item removido
unshift(item)acrescenta no começonovo length
shift()remove do começoo item removido

push e pop mexem na ponta direita; unshift e shift na ponta esquerda.

unshift e shift são mais caros quando a lista é grande, porque todos os itens

mudam de posição.

O detalhe que gera bug: **pop devolve o item removido, push devolve o

tamanho.** Nenhum dos dois devolve a lista. Quem escreve `const lista =

tarefas.pop()` fica com o item, não com a lista.

O exemplo vai método por método e imprime o que cada um devolve e como a

lista ficou depois, que é a forma de não confundir os dois papéis.

push devolve o length: 4 | lista: [ 1, 2, 3, 4 ] — devolveu 4 e a lista

cresceu. pop devolve o item removido: 4 | lista: [ 1, 2, 3 ] — devolveu o 4

que saiu. unshift devolve o length: 4 | lista: [ 0, 1, 2, 3 ] e

shift devolve o item removido: 0 | lista: [ 1, 2, 3 ].

Repare que a lista volta a [ 1, 2, 3 ] depois das quatro operações, e foi

exatamente onde começou. Cada linha mostra o par completo: **o que o método

devolve e o que a lista ficou**. O nome da propriedade length e o nome

item removido nas duas primeiras linhas dizem qual dos dois é cada caso.

splice é o método que muda no meio: recebe posição, quantos remover e o que

colocar no lugar, e devolve os itens removidos.

const lista = [1, 2, 3, 4];
const removidos = lista.splice(1, 2, 'X');
// removidos = [2, 3], lista = [1, 'X', 4]

A linha do exemplo é splice devolve: [ 2, 3 ] | sobra: [ 1, 'X', 4 ], e os

dois lados batem com o código do bloco acima. A posição 1 é o 2, a

quantidade 2 tira o 2 e o 3, e o 'X' entra no lugar deles. Por isso o

splice é o método mais útil dos dois: o slice não coloca nada no lugar.

slice é o par não destrutivo de splice: devolve um array novo sem mexer no

original, e por isso const lista = tarefas.slice() é a forma de copiar uma

lista.

O exemplo mostra os dois na mesma linha, e a segunda parte é a prova do

parágrafo: slice: [ 2, 3 ] | o original continua: [ 1, 'X', 4 ]. O slice

devolveu [ 2, 3 ] — os mesmos itens que o splice tinha removido — e a lista

continua com o splice já aplicado. O slice pegou do resultado anterior

porque o splice tinha mudado a lista antes.

at e índice negativo

at aceita índice negativo e conta de trás — o último item é -1:

console.log(['a', 'b', 'c'].at(-1));   // 'c'

Com o colchete, [-1] não funciona: é a chave '−1' de um objeto, e devolve

undefined.

O exemplo põe os dois lado a lado, e é o par que fixa o método:

['a', 'b', 'c'].at(-1): c | o ultimo: c e, na linha seguinte,

colchete com -1 nao funciona: undefined. O mesmo índice negativo produziu uma

letra pelo at e nada pelo colchete.

O undefined não é esquisitice: o array tem as propriedades '0', '1', '2'

e length. O colchete procura a propriedade '−1', que não existe entre elas.

O at faz conta a partir do fim, e é por isso que ele aceita o sinal.

O at também aceita índice positivo, então at(1) e [1] dão o mesmo item. A

diferença é só o negativo.

Copiar array de verdade

Copiar com const copia = tarefas não copia: as duas variáveis apontam para

o mesmo array, e mexer em uma mexe na outra. A cópia de verdade usa spread ou

slice, e cria um array novo:

const copia = [...tarefas];
copia.push('dormir');
console.log(tarefas.length);   // 2: o original não mudou

Para comparar dois arrays, === compara as referências e sempre dá false para

listas diferentes com mesmo conteúdo. O que compara conteúdo é

JSON.stringify(a) === JSON.stringify(b), ou o método includes quando o que se

pergunta é se um item está dentro.

A cópia do exemplo é uma linha só, e os três dados dela são a prova:

`original: [ 'estudar', 'treinar' ] | copia: [ 'estudar', 'treinar', 'dormir' ] |

mesma referencia: false. O push('dormir')` foi aplicado na cópia, o original

continua com dois itens, e o false do === diz que são dois arrays

diferentes. Com const copia = original, essa terceira parte sairia true e as

duas listas mudariam juntas.

As três comparações do fim do exemplo são a resposta completa para a pergunta

"esses dois arrays são iguais". '===' em arrays diferentes: false é o que a

comparação por referência devolve para [1, 2] contra outro [1, 2].

JSON.stringify compara conteudo: true é o mesmo par comparado pelo conteúdo, e

includes pergunta se o item esta dentro: true é outra pergunta — não é sobre

igualdade da lista, é sobre pertencer.

A última linha é a forma real do dado que vem de fora:

da api: estudar, treinar. A resposta da API é um objeto com tarefas sendo um

array de objetos, e a linha extrai os dois textos com map e join. É o mesmo

caminho que o map da próxima aula percorre em detalhe.

Exemplo

// Criar, ler e alterar array. O exemplo mostra os tres jeitos de criar,
// os metodos das pontas e a diferenca entre copiar e apontar.
const tarefas = ['estudar', 'treinar'];

console.log('literal:', tarefas);
console.log('indice 0:', tarefas[0], '| indice 1:', tarefas[1], '| length:', tarefas.length);

/* criar de tres jeitos */
console.log('literal:', [1, 2, 3]);
console.log('new Array(3) sao tres posicoes vazias:', new Array(3).length, JSON.stringify(new Array(3)));
console.log('Array.of:', Array.of(1, 2, 3));
console.log('array vazio:', [], '| Array.isArray([]):', Array.isArray([]), '| de uma string:', Array.isArray('Ana'));

/* transformar outra coisa em array */
console.log("Array.from('Ana'):", Array.from('Ana'));
console.log('Array.from com funcao:', Array.from({ length: 3 }, (_, i) => i * 2));
console.log('concat:', [].concat([1, 2], [3]));

/* acrescentar e remover nas pontas */
const lista = [1, 2, 3];
console.log('push devolve o length:', lista.push(4), '| lista:', lista);
console.log('pop devolve o item removido:', lista.pop(), '| lista:', lista);
console.log('unshift devolve o length:', lista.unshift(0), '| lista:', lista);
console.log('shift devolve o item removido:', lista.shift(), '| lista:', lista);

/* splice: muda no meio e devolve os removidos */
const meio = [1, 2, 3, 4];
const removidos = meio.splice(1, 2, 'X');
console.log('splice devolve:', removidos, '| sobra:', meio);

/* slice: o par nao destrutivo de splice */
console.log('slice:', [1, 2, 3, 4].slice(1, 3), '| o original continua:', meio);

/* length apaga por atribuicao */
const cortavel = [1, 2, 3];
cortavel.length = 1;
console.log('length = 1 corta:', cortavel);

/* at e indice negativo */
console.log("['a', 'b', 'c'].at(-1):", ['a', 'b', 'c'].at(-1), '| o ultimo:', ['a', 'b', 'c'].at(-1));
console.log('colchete com -1 nao funciona:', ['a', 'b', 'c'][-1]);

/* copiar de verdade: com spread ou slice */
const original = ['estudar', 'treinar'];
const copia = [...original];
copia.push('dormir');
console.log('original:', original, '| copia:', copia, '| mesma referencia:', original === copia);

/* comparar conteudo, nao referencia */
console.log("'===' em arrays diferentes:", [1, 2] === [1, 2]);
console.log('JSON.stringify compara conteudo:', JSON.stringify([1, 2]) === JSON.stringify([1, 2]));
console.log('includes pergunta se o item esta dentro:', [1, 2, 3].includes(2));

/* o array que vem de API: a forma real */
const resposta = { tarefas: [{ id: 1, texto: 'estudar' }, { id: 2, texto: 'treinar' }] };
console.log('da api:', resposta.tarefas.map((t) => t.texto).join(', '));

Saída real

literal: [ 'estudar', 'treinar' ]
indice 0: estudar | indice 1: treinar | length: 2
literal: [ 1, 2, 3 ]
new Array(3) sao tres posicoes vazias: 3 [null,null,null]
Array.of: [ 1, 2, 3 ]
array vazio: [] | Array.isArray([]): true | de uma string: false
Array.from('Ana'): [ 'A', 'n', 'a' ]
Array.from com funcao: [ 0, 2, 4 ]
concat: [ 1, 2, 3 ]
push devolve o length: 4 | lista: [ 1, 2, 3, 4 ]
pop devolve o item removido: 4 | lista: [ 1, 2, 3 ]
unshift devolve o length: 4 | lista: [ 0, 1, 2, 3 ]
shift devolve o item removido: 0 | lista: [ 1, 2, 3 ]
splice devolve: [ 2, 3 ] | sobra: [ 1, 'X', 4 ]
slice: [ 2, 3 ] | o original continua: [ 1, 'X', 4 ]
length = 1 corta: [ 1 ]
['a', 'b', 'c'].at(-1): c | o ultimo: c
colchete com -1 nao funciona: undefined
original: [ 'estudar', 'treinar' ] | copia: [ 'estudar', 'treinar', 'dormir' ] | mesma referencia: false
'===' em arrays diferentes: false
JSON.stringify compara conteudo: true
includes pergunta se o item esta dentro: true
da api: estudar, treinar
Aula 2

Transformar: map, filter e reduce

Transformar: map, filter e reduce

Os três métodos que mais aparecem em React Native são map, filter e

reduce. Todos os três recebem uma função e devolvem um array novo — e é

isso que importa: nenhum dos três altera o array original. É o que permite que a

tela receba um valor novo e se redesenhe, sem estado se corromper.

A lista do exemplo é a base de tudo: três tarefas com id, texto e feita, e

as três primeiras linhas do console já mostram a propriedade do parágrafo.

original: [ 'estudar', 'treinar', 'dormir' ] é a lista intacta;

map: [ 'ANA', 'BRUNO' ] devolveu um array novo do mesmo tamanho; e

map nao altera o original: [ 'ana', 'bruno' ] prova que o array de entrada

continua minúsculo depois das transformações. É o mesmo array nas três linhas, e

só uma delas mudou.

MétodoDevolveA função recebeA função devolve
maparray do mesmo tamanhoitemo item transformado
filtersó os itens que passaramitemtrue ou false
reduceum valor acumulado: é o que reduzir a lista fazitem, acumuladoro novo acumulador

map: transformar item por item

map chama a função uma vez para cada item e monta um array com os retornos. O

tamanho da saída é o tamanho da entrada:

const nomes = ['ana', 'bruno'];
console.log(nomes.map((nome) => nome.toUpperCase()));
// ['ANA', 'BRUNO']

O segundo argumento é o índice, e o terceiro é o array inteiro. map é o que

desenha lista de componente: um View para cada item, com o item no meio.

A linha do exemplo que usa o índice é map com indice: [ '0: ana', '1: bruno' ].

A função recebeu (nome, indice) e montou o texto com os dois — e é assim que o

map numera uma linha de lista ou monta o texto de um botão que precisa saber

qual é o seu.

O erro clássico de map é o elemento sem chave, key:

{tarefas.map((tarefa) => <Item key={tarefa.id} tarefa={tarefa} />)}

Sem key, o React Native não sabe qual item da tela corresponde a qual item da

lista e a atualização sai errada. A chave é o id, nunca o índice.

filter: ficar com o que interessa

filter mantém os itens para os quais a função devolveu true:

const tarefas = [
  { id: 1, texto: 'estudar', feita: false },
  { id: 2, texto: 'treinar', feita: true },
];
console.log(tarefas.filter((t) => !t.feita).length);   // 1

filter não altera o array original e devolve um array com tamanho **menor ou

igual**. Ele é truthy e falsy: devolver o próprio objeto também passa, mas

devolver true ou false é mais legível.

O exemplo filtra as três tarefas e imprime

filter: [ 'estudar', 'dormir' ] | tamanho: 2. Entrada com três itens, saída

com dois — e são exatamente os dois com feita: false, porque a condição foi

!t.feita. A linha seguinte usa a condição invertida e sai

filter com truthy: [ 'treinar' ]: uma linha só, porque t.feita devolveu o

próprio booleano do objeto.

As duas linhas mostram o comportamento truthy e falsy na prática. A primeira

pede !t.feita, que é true ou false explícito; a segunda pede t.feita, que

já é o booleano do objeto. O filter aceitaria qualquer um dos dois — e também

aceitaria o objeto inteiro, que é truthy e por isso passa.

reduce: um valor só no fim

reduce percorre o array acumulando. O segundo argumento é o **valor inicial do

acumulador** e é obrigatório na forma que funciona sem valor inicial:

const numeros = [1, 2, 3];
console.log(numeros.reduce((acc, n) => acc + n, 0));   // 6

Com objeto no acumulador, reduce vira a forma de montar o agrupamento que a

tela precisa:

const porFeita = tarefas.reduce((acc, t) => {
  acc[t.feita ? 'prontas' : 'pendentes'] += 1;
  return acc;
}, { prontas: 0, pendentes: 0 });

O detalhe que trava quem está começando: reduce não devolve nada se o

acumulador não voltar na função. A última linha do callback tem que ser return.

Sem ela, o reduce não acusa erro nenhum — devolve undefined em silêncio, e o

erro só aparece mais adiante, quando esse valor entra numa conta e vira NaN. É

o defeito mais silencioso desta lista, porque o código roda inteiro sem reclamar.

O exemplo tem três reduce que dão conta, e um quarto que dá o defeito.

reduce soma: 6 e reduce conta: 3 são as duas formas simples — a primeira

soma os números, a segunda só conta as voltas. O terceiro usa o acumulador

objeto e sai reduce com objeto no acumulador: { prontas: 1, pendentes: 2 }:

das três tarefas, uma está pronta e duas estão pendentes.

O quarto é o caso do parágrafo, e sai em duas linhas:

reduce sem return: undefined | typeof: undefined e

o undefined aparece depois na conta: NaN. O callback escrevia acc + n sem

devolver, então o acumulador sumiu logo na primeira volta — o reduce não

acusou erro, e o resultado é undefined. A linha seguinte mostra onde o estrago

aparece de verdade: undefined + 1 é NaN, longe do reduce que causou.

Os de buscar e os de testar

  • find devolve o primeiro item que passa no teste, ou undefined.
  • findIndex devolve a posição do primeiro, ou -1.
  • some devolve true se algum passa.
  • every devolve true se todos passam.
tarefas.find((t) => t.feita).id;        // 2
tarefas.findIndex((t) => t.feita);      // 1
tarefas.some((t) => t.feita);           // true
tarefas.every((t) => t.texto);          // true

As seis linhas do exemplo cobrem os quatro métodos e dois casos de borda.

find: 2 devolveu o id da primeira tarefa feita, e findIndex: 1 devolveu a

posição dela — mesmo item, dois números diferentes, porque um pergunta "qual" e o

outro pergunta "onde". some: true | every: true confirma os dois testes: pelo

menos uma está feita, e todas têm texto.

A linha find sem resultado: undefined é o find sem id atrás — quando não

acha nada, devolve o próprio undefined, e escrever .id nessa linha daria

TypeError. Por isso o find no app costuma vir com guarda: `const achado =

tarefas.find(...); if (achado) { ... }`.

O includes aparece na linha seguinte com os dois lados:

includes: false | no array de texto: true. A primeira é tarefas.includes({})

comparando contra um objeto novo — false, porque o includes compara

referência, e um objeto novo não é nenhum dos da lista. A segunda é o caso de

uso real, ['a', 'b'].includes('b').

includes responde se um valor exato está na lista; flatMap transforma e

achata um nível; sort e reverse ordenam e invertem no lugar — são os dois

únicos desta lista que alteram o array original. Para iterar array sem

alterar o original, quem resolve é slice: slice devolve um array novo com o

pedaço pedido, e o array de origem fica como estava. É também o slice que

flat e splice não substituem — cortar e filtrar são operações diferentes.

O flatMap e o flat do exemplo estão em duas linhas: flatMap: [ 1, 10, 2, 20 ]

e flat: [ 1, 2, 3, [ 4 ] ]. O primeiro transforma cada número em um par

[n, n * 10] e achata o resultado, então dois itens viram quatro. O segundo

achata dois níveis e o que sobrou aninhado continua aninhado — [ 4 ] dentro do

array é o resto que o flat(2) não alcançou.

E o reverse é reverse: [ 3, 2, 1 ], com o original intacto logo abaixo:

o original nao foi mexido: [ 10, 9, 1 ]. O exemplo espalha o array com

[...numeros] antes de cada sort, justamente porque o sort altera no lugar.

sort sem argumento compara como texto, e é por isso que [10, 9, 1].sort() dá

[1, 10, 9]: '10' vem antes de '9' porque '1' < '9'. Para número, o

argumento é a comparação:

console.log([10, 9, 1].sort((a, b) => a - b));   // [1, 9, 10]

As duas linhas do exemplo são sort sem argumento (como texto): [ 1, 10, 9 ] e

sort com comparacao: [ 1, 9, 10 ]. Mesmo array, mesmo sort, duas ordens: a

primeira é a comparação caractere a caractere de '10', '9', '1'; a

segunda é a subtração a - b, que devolve número em vez de booleano. O a - b

é o que diz ao sort qual item vem antes.

A última linha do exemplo junta os três em uma cadeia só:

encadeado: ESTUDAR, DORMIR. Filtrou as pendentes, transformou os textos em

maiúsculas e juntou com join. É a forma que o app usa para montar a linha de

resumo, e cada método da cadeia devolve o array que o próximo espera.

Exemplo

// map, filter e reduce: os tres que transformam lista, e os que so
// procuram. Todos devolvem array novo e nao mexem no original.
const tarefas = [
  { id: 1, texto: 'estudar', feita: false },
  { id: 2, texto: 'treinar', feita: true },
  { id: 3, texto: 'dormir', feita: false },
];

console.log('original:', tarefas.map((t) => t.texto));

/* map: transforma item por item, saida do mesmo tamanho */
const nomes = ['ana', 'bruno'];
console.log('map:', nomes.map((nome) => nome.toUpperCase()));
console.log('map com indice:', nomes.map((nome, indice) => `${indice}: ${nome}`));
console.log('map nao altera o original:', nomes);

/* filter: fica com o que passou no teste */
const pendentes = tarefas.filter((t) => !t.feita);
console.log('filter:', pendentes.map((t) => t.texto), '| tamanho:', pendentes.length);
console.log('filter com truthy:', tarefas.filter((t) => t.feita).map((t) => t.texto));

/* reduce: um valor so no fim */
console.log('reduce soma:', [1, 2, 3].reduce((acc, n) => acc + n, 0));
console.log('reduce conta:', tarefas.reduce((acc) => acc + 1, 0));
console.log('reduce com objeto no acumulador:', tarefas.reduce((acc, t) => {
  acc[t.feita ? 'prontas' : 'pendentes'] += 1;
  return acc;                       // sem este return o acumulador some
}, { prontas: 0, pendentes: 0 }));

// sem o return, o acumulador some no meio das voltas

/* o reduce sem return no callback nao acusa erro: devolve undefined */
const semRetorno = [1, 2, 3].reduce((acc, n) => { acc + n; }, 0);
console.log('reduce sem return:', semRetorno, '| typeof:', typeof semRetorno);
console.log('o undefined aparece depois na conta:', semRetorno + 1);

/* os que procuram e os que testam */
console.log('find:', tarefas.find((t) => t.feita).id);
console.log('findIndex:', tarefas.findIndex((t) => t.feita));
console.log('find sem resultado:', tarefas.find((t) => t.texto === 'correr'));
console.log('some:', tarefas.some((t) => t.feita), '| every:', tarefas.every((t) => t.texto));
console.log('includes:', tarefas.includes({}), '| no array de texto:', ['a', 'b'].includes('b'));

/* flatMap transforma e achata um nivel */
console.log('flatMap:', [1, 2].flatMap((n) => [n, n * 10]));
console.log('flat:', [1, [2, [3, [4]]]].flat(2));

/* sort e reverse sao os que alteram no lugar */
const numeros = [10, 9, 1];
console.log('sort sem argumento (como texto):', [...numeros].sort());
console.log('sort com comparacao:', [...numeros].sort((a, b) => a - b));
console.log('reverse:', [1, 2, 3].reverse());
console.log('o original nao foi mexido:', numeros);

/* o erro do map em quem nao e array */
try {
  'Ana'.map((letra) => letra);
} catch (erro) {
  console.log('map em string:', erro.constructor.name, '-', erro.message);
}

/* encadeamento: filtrar, transformar, contar */
console.log('encadeado:', tarefas
  .filter((t) => !t.feita)
  .map((t) => t.texto.toUpperCase())
  .join(', '));

Saída real

original: [ 'estudar', 'treinar', 'dormir' ]
map: [ 'ANA', 'BRUNO' ]
map com indice: [ '0: ana', '1: bruno' ]
map nao altera o original: [ 'ana', 'bruno' ]
filter: [ 'estudar', 'dormir' ] | tamanho: 2
filter com truthy: [ 'treinar' ]
reduce soma: 6
reduce conta: 3
reduce com objeto no acumulador: { prontas: 1, pendentes: 2 }
reduce sem return: undefined | typeof: undefined
o undefined aparece depois na conta: NaN
find: 2
findIndex: 1
find sem resultado: undefined
some: true | every: true
includes: false | no array de texto: true
flatMap: [ 1, 10, 2, 20 ]
flat: [ 1, 2, 3, [ 4 ] ]
sort sem argumento (como texto): [ 1, 10, 9 ]
sort com comparacao: [ 1, 9, 10 ]
reverse: [ 3, 2, 1 ]
o original nao foi mexido: [ 10, 9, 1 ]
map em string: TypeError - "Ana".map is not a function
encadeado: ESTUDAR, DORMIR