Coleções indexadas

Uma coleção indexada é uma estrutura de dados em que os elementos são armazenados e acessados usando índices numerados. Os valores armazenados em uma coleção indexada recebem índices numerados a partir de 0, um padrão chamado "zero-indexing". Assim, é possível acessar os valores armazenados em uma coleção indexada referenciando os índices dela.

Matriz

Uma matriz é um contêiner que pode conter zero ou mais valores de qualquer tipo de dados, incluindo objetos complexos ou outras matrizes. Os valores armazenados em uma matriz às vezes são chamados de "elementos" da matriz.

Criar uma matriz

Assim como nos tipos de dados primitivos, há duas abordagens para criar uma matriz: como um literal de matriz ou invocando o construtor Array() integrado do JavaScript com new Array(). Atribuir uma matriz a uma variável oferece uma maneira altamente portátil e iterável de atribuir vários valores a um único identificador.

A sintaxe literal da matriz usa um conjunto de colchetes ([]) ao redor de zero ou mais valores de dados separados por vírgulas:

const myArray = [];

A sintaxe do construtor de matriz usa o objeto Array integrado do JavaScript como um construtor com a palavra-chave new:

const myArray = new Array();

As sintaxes de literal de matriz e de construtor de matriz permitem preencher uma matriz com informações quando ela é criada, embora as sintaxes sejam um pouco diferentes na forma como esses valores são definidos. A sintaxe literal da matriz usa valores separados por vírgula entre os colchetes, que têm a mesma aparência da matriz resultante:

const myArray = [ true, null, "String", false ];

myArray;
> [ true, null, "String", false ]

A sintaxe do construtor de matriz usa valores separados por vírgula como argumentos, com uma exceção comportamental especial:

const myArray = new Array( true, null, "String", false );

myArray;
> Array(4) [ true, null, "String", false ]

Quando um único valor numérico é transmitido ao construtor Array, esse valor não é atribuído à posição zero na matriz resultante. Em vez disso, uma matriz é criada com esse número de slots vazios para valores. Isso não impõe limitações à matriz. Os itens podem ser adicionados e removidos dele da mesma forma que um literal de matriz.

// Firefox:\
const myArray = new Array( 10 );

myArray;
> Array(10) [ <10 empty slots> ]
// Chrome:
const myArray = new Array( 10 );

myArray;
> (10) [empty × 10]

As matrizes contendo slots vazios (às vezes chamadas de "matrizes esparsas") são casos especiais. Em vez de conter um valor undefined ou explicitamente null, os slots vazios são muitas vezes, mas nem sempre, tratados como valores undefined em outro lugar do idioma.

Você pode criar acidentalmente uma matriz esparsa usando a sintaxe literal da matriz ao omitir um valor entre as vírgulas ao criar um literal de matriz:

const myArray = [ true,, true, false ];

myArray;
> Array(4) [ true, <1 empty slot>, true, false ]

Apesar de não ser tratado como um valor significativo em todos os contextos, um slot vazio é considerado no tamanho total da matriz, o que pode levar a resultados inesperados ao iterar os valores de uma matriz:

const myArray = [ 1,, 3, 4 ];

myArray.length;
> 4

for( const myValue of myArray ) {
  console.log( myValue + 10 );
}
> 11
> NaN
> 13
> 14

Esse comportamento é uma consequência de algumas das primeiras decisões de design do JavaScript. Evite usar matrizes esparsas no desenvolvimento moderno.

Assim como nos primitivos, um literal de matriz herda propriedades e métodos do construtor correspondente. Como uma matriz é uma forma especial de objeto, a sintaxe literal da matriz e a sintaxe new Array() criam resultados funcionalmente idênticos: um objeto que herda o protótipo do construtor Array.

const arrayLiteral = [];
const arrayConstructor = new Array();

typeof arrayLiteral;
> "object"

arrayLiteral;
> Array []
    length: 0
    <prototype>: Array []

typeof arrayConstructor;
> "object"

arrayConstructor;
> Array []
    length: 0
    <prototype>: Array []

Como os dois resultados são idênticos e a sintaxe do literal de matriz é mais concisa e literal, recomendamos sempre usar a sintaxe literal da matriz em vez da new Array().

Acessar valores da matriz

É possível acessar elementos individuais dentro da matriz usando a notação de colchetes, um conjunto de colchetes ([]) após a matriz ou o identificador que contém um número que se refere ao índice desse elemento:


[ "My string", "My other string" ][ 1 ];
> "My other string"

const myArray = [ "My string", 50, true ];

myArray[ 0 ];
> "My string"

myArray[ 1 ];
> 50

myArray[ 2 ];
> true

As matrizes em JavaScript não são associativas, o que significa que não é possível usar uma string arbitrária como índice. No entanto, os valores numéricos usados para acessar elementos em uma matriz são convertidos em um valor de string em segundo plano, o que significa que você pode usar um valor de string que contenha apenas caracteres numéricos:

const myArray = [ "My string", 50, true ];

myArray[ 2 ];
> true

myArray[ "2" ];
> true

A tentativa de acessar um elemento fora dos definidos na matriz resulta em undefined, não em um erro:

const myArray = [ "My string", 50, true ];

myArray[ 9 ];
> undefined

Desestruturando atribuição

A desestruturação de atribuição é uma maneira concisa de extrair um intervalo de valores de matrizes ou objetos e atribuí-los a um conjunto de identificadores, um processo às vezes chamado de "descompactar" a estrutura de dados original, mas não modificar a matriz ou o objeto original.

A desestruturação da atribuição usa uma lista de identificadores do tipo matriz ou objeto para acompanhar os valores. Na forma mais simples, chamada de desestruturação de padrão de vinculação, cada valor é descompactado da matriz ou do objeto e atribuído a uma variável correspondente, inicializado usando let ou const (ou var):

const myArray = [ "A string", "A second string" ];
const [ myFirstElement, mySecondElement ] = myArray;

const myObject = { firstValue: false, secondValue: true };
const { myProp, mySecondProp } = myObject;

myFirstElement;
> "My string"

mySecondElement;
> "Second string"

myProp;
> false

mySecondProp;
> true

Use chaves ({}) para desestruturar um objeto e colchetes ([]) para desestruturar uma matriz.

const myArray = [ false, true ];
const myObject = { firstValue: false, secondValue: true };

const [ myProp, mySecondProp ] = myObject;
> Uncaught TypeError: myObject is not iterable

const { myElement, mySecondElement } = myArray;

myElement
> undefined

mySecondElement;
> undefined

A desestruturação de uma matriz acontece em ordem sequencial, da esquerda para a direita. Cada identificador na atribuição de desestruturação corresponde ao elemento da matriz com o mesmo índice:

const myArray = [ 1, 2, 3 ];
const [ myElement, mySecondElement, myThirdElement ] = myArray;

myElement;
> 1

mySecondElement;
> 2

myThirdElement;
> 3

Esse também é o comportamento padrão ao desestruturar um objeto. No entanto, se os identificadores usados na atribuição de desestruturação corresponderem às chaves das propriedades do objeto, eles serão preenchidos com os valores de propriedade correspondentes, independentemente da ordem em que estiverem especificados:

const myObject = { firstValue: 1, secondValue: 2, thirdValue 3 };
const { secondValue, thirdValue, firstValue } = myObject;

firstValue;
> 1

secondValue;
> 2

thirdValue;
> 3

Os elementos podem ser ignorados com a omissão de um identificador:

const myArray = [ 1, 2, 3 ];
const [ firstValue,, secondValue ] = myArray;

firstValue;
> 1

secondValue;
> 3

A sintaxe de desestruturação também permite atribuir valores padrão caso um valor desestruturado seja um slot vazio, como no caso de uma matriz esparsa, ou um valor undefined.

const myArray = [ true, ];
const [ firstValue = "Default string.", secondValue = "Default string." ] = myArray;

firstValue;
> true

secondValue;
> "Default string."

A desconstrução não força valores para tipos específicos. Isso significa que valores "falsy", como strings vazias ("") ou null, ainda são considerados valores desconstruídos significativos:

const myArray = [ false, null, 0, "",, undefined ];
const [ falseValue = true, nullValue = true, zeroValue = true, emptyStringValue = true, emptySlot = true, undefinedValue = true ] = myArray;

falseValue;
> false;

nullValue;
> null

zeroValue;
> 0

emptyStringValue;
> ""

emptySlot;
> true

undefinedValue;
> true

Operador de propagação

Use o operador de propagação (...), introduzido no ES6, para expandir uma estrutura de dados iterável, como uma matriz, string ou literal de objeto em elementos individuais. O operador de propagação é imediatamente seguido pela estrutura de dados a ser expandida ou pelo identificador de uma variável que contém essa estrutura de dados.

const myArray = [ 1, 2, 3 ];

console.log( ...myArray );
> 1 2 3

A sintaxe de propagação é usada principalmente para copiar e combinar matrizes:

const myArray = [ 4, 5, 6 ];
const mySecondArray = [1, 2, 3, ...myArray ];

mySecondArray;
> Array(6) [ 1, 2, 3, 4, 5, 6 ]

A sintaxe de propagação pode ser usada apenas nos seguintes contextos:

Para matrizes e strings, a sintaxe de propagação se aplica somente quando zero ou mais argumentos em uma chamada de função ou elementos em uma matriz são esperados. O primeiro exemplo de sintaxe de operador de propagação nesta seção funciona porque transmite ...myArray como um argumento para o método console.log integrado.

Por exemplo, não é possível atribuir os dados que estão sendo distribuídos a uma variável fora de outra matriz:

const myArray = [ 1, 2, 3 ];
const spreadVariable = ...myArray;
> Uncaught SyntaxError: Unexpected token '...'

Mas você copia uma matriz espalhando a matriz original em um literal de matriz:

const myArray = [ 1, 2, 3 ];
const spreadArray = [ ...myArray ];

spreadArray;
> Array(3) [ 1, 2, 3 ]

Para mesclar os elementos que compõem duas ou mais matrizes em uma única matriz:

const myArray = [ 1, 2, 3 ];
const mySecondArray = [ 4, 5, 6 ];
const myNewArray = [ ...myArray, ...mySecondArray ];

myNewArray;
> Array(6) [ 1, 2, 3, 4, 5, 6 ]

Ou, para transmitir elementos de uma matriz como argumentos individuais em uma chamada de função:

const myArray = [ true, false ];
const myFunction = ( myArgument, mySecondArgument ) => {
    console.log( myArgument, mySecondArgument );
};

myFunction( ...myArray );
> true false

O operador de propagação foi expandido para funcionar com literais de objetos no ES2018 (link em inglês). Assim como nas matrizes, é possível usar o operador de propagação para duplicar ou mesclar objetos:

const myObj = { myProperty : true };
const mySecondObj = { ...myObj };

mySecondObj;
> Object { myProperty: true }
const myFirstObj = { myProperty : true };
const mySecondObj = { additionalProperty : true };
const myMergedObj = { ...myFirstObj, ...mySecondObj };

myMergedObj;
> Object { myProperty: true, additionalProperty: true }

O operador de propagação cria cópias "superfícies". Isso significa que ele não copia o protótipo do objeto original e as propriedades não enumeradas.

const myCustomPrototype = { protoProp: "My prototype." };
const myObj = Object.create( myCustomPrototype, {
    myEnumerableProp: {
        value: true,
        enumerable: true
    },
    myNonEnumerableProp: {
        value: false,
        enumerable: false
    }
});
const myNewObj = { ...myObj };

myObj;
> Object { myEnumerableProp: true, … }
    myEnumerableProp: true
    myNonEnumerableProp: false
    <prototype>: Object { protoProp: "My prototype." }

myNewObj;
> Object { myEnumerableProp: true }
    myEnumerableProp: true
    <prototype>: Object { … }

Tenha em mente que matrizes e objetos não podem ser usados de forma intercambiável. Não é possível espalhar um objeto em uma matriz ou uma matriz em um objeto.

Operador "rest"

Embora a sintaxe do próprio operador seja a mesma, o operador REST (...) executa a função oposta com base no contexto em que é usado. Em vez de expandir uma estrutura de dados iterável em elementos individuais, como acontece na atribuição de desestruturação ou como um parâmetro de função, o operador REST combina elementos em uma estrutura de dados iterável. O nome vem do fato de que é usado para reunir "o restante" de um conjunto de valores de dados.

Quando usada com a atribuição de desestruturação, a sintaxe é chamada de "propriedade de repouso".

const myArray = [ "First", "Second", "Third", "Fourth", "Fifth" ];

[ myFirstElement, mySecondElement, ...remainingElements ] = myArray;

myFirstElement;
> "First"

mySecondElement;
> "Second"

remainingElements;
> Array(3) [ "Third", "Fourth", "Fifth"]

Quando usada para fornecer um número indefinido de argumentos a uma função, a sintaxe é chamada de sintaxe "parâmetro rest":

function myFunction( ...myParameters ) {
    let result = 0;
    myParameters.forEach( ( myParam ) => {
        result += myParam;
    });
    return result;
};

myFunction( 2, 2 );
> 4

myFunction( 1, 1, 1, 10, 5 );
> 18

myFunction( 10, 11, 25 );
> 46

%TypedArray%

Matrizes tipadas são um recurso do ES6 projetado para armazenar dados binários estruturados, por exemplo, ao trabalhar com arquivos enviados ou WebGL.

Assim como acontece com os Símbolos, a função intrínseca %TypedArray% (geralmente documentada como %TypedArray% ou @@TypedArray para que não possa ser confundida com uma propriedade global) não é uma função de construtor no sentido convencional, e não é possível invocá-la com new ou chamá-la diretamente. Em vez disso, %TypedArray% refere-se a uma superclasse pai de construtores individuais, cada um dos quais funciona com um formato específico de dados binários. A superclasse intrínseca %TypedArray% fornece propriedades e métodos utilitários que todas as subclasses de construtor %TypedArray% e as respectivas instâncias herdam.

Teste seu conhecimento

Considerando `const myArray = [ 30, 50, 70 ];`, o que `myArray[1]` retorna?

50
30
70

Se "myArray" tiver três valores, o que "myArray[9]" retornará?

Undefined
Uma mensagem de erro
9
Null