Colecciones indexadas
En JavaScript, las colecciones indexadas son estructuras de datos que almacenan elementos y permiten acceder a ellos mediante un índice numérico.
Arrays o vectores
Pero a menudo necesitamos una colección ordenada, donde tenemos un 1ro, un 2do, un 3er elemento y así sucesivamente. Por ejemplo, necesitamos almacenar una lista de algo: usuarios, bienes, elementos HTML, etc.
No es conveniente usar objetos aquí, porque no proveen métodos para manejar el orden de los elementos. No podemos insertar una nueva propiedad “entre” los existentes. Los objetos no están hechos para eso.
Existe una estructura llamada Array
(llamada en español arreglo o matriz/vector) para almacenar colecciones ordenadas.
En JavaScript, los arrays no son primitivas, sino objetos Array con las siguientes características básicas:
- Las matrices de JavaScript son redimensionables y pueden contener una mezcla de diferentes tipos de datos. (Cuando esas características no sean deseables, utilice en su lugar arrays tipados).
- Los Arrays de JavaScript no son array asociativos y, por lo tanto, no se puede acceder a los elementos de la matriz utilizando cadenas arbitrarias como índices, sino que se debe acceder utilizando enteros no negativos (o su respectiva forma de cadena) como índices.
- Las matrices de JavaScript están indexadas a cero: el primer elemento de una matriz está en el índice 0, el segundo en el índice 1, y así sucesivamente - y el último elemento está en el valor de la propiedad
length
de la matriz menos 1. - Las operaciones de copia de arrays de JavaScript crean copias superficiales. (Todas las operaciones de copia estándar incorporadas con cualquier objeto JavaScript crean copias superficiales, en lugar de copias profundas).
Índices
Los objetos array no pueden utilizar cadenas arbitrarias como índices de elementos (como en un array asociativo), sino que deben utilizar enteros no negativos (o su respectiva forma de cadena). El establecimiento o acceso a través de números no enteros no establecerá o recuperará un elemento de la propia lista de la matriz, sino que establecerá o accederá a una variable asociada con la colección de propiedades de objeto de esa matriz. Las propiedades de objeto de la matriz y la lista de elementos de la matriz son independientes, y las operaciones de recorrido y mutación de la matriz no se pueden aplicar a estas propiedades con nombre.
❌
Error
La sintaxis de JavaScript requiere que se acceda a las propiedades que empiezan por un dígito utilizando la notación de corchetes en lugar de la notación de puntos. También es posible entrecomillar los índices de la matriz (por ejemplo, years['2']
en lugar de years[2]
), aunque no suele ser necesario.
El motor JavaScript convierte el 2 de years[2]
en una cadena mediante una conversión implícita toString
. Como resultado, '2'
y '02'
se referirían a dos ranuras diferentes en el objeto years
, y el siguiente ejemplo podría ser true
:
✅
Correcto
Sólo years['2']
es un índice real del array. years['02']
es una propiedad de cadena arbitraria que no será visitada en la iteración del array.
Relación entre la longitud y las propiedades numéricas
La propiedad de longitud de un array JavaScript y las propiedades numéricas están conectadas.
Varios de los métodos de array incorporados (por ejemplo, join()
, slice()
, indexOf()
, etc.) tienen en cuenta el valor de la propiedad length de un array cuando se llaman.
Otros métodos (por ejemplo, push()
, splice()
, etc.) también resultan en actualizaciones de la propiedad length de un array.
Al establecer una propiedad en una matriz JavaScript, cuando la propiedad es un índice de matriz válido y ese índice está fuera de los límites actuales de la matriz, el motor actualizará la propiedad de longitud de la matriz en consecuencia:
Aumentar la longitud.
Sin embargo, al reducir la propiedad de longitud se eliminan elementos.
Métodos de matrices y ranuras vacías
Las ranuras vacías en matrices dispersas se comportan de forma inconsistente entre los métodos de matrices. Por lo general, los métodos más antiguos omiten las ranuras vacías, mientras que los más recientes las tratan como undefined
.
Métodos de copia y métodos de mutación
Algunos métodos no mutan el array existente sobre el que se ha llamado al método, sino que devuelven un nuevo array. Lo hacen accediendo primero a this.constructor[Symbol.species]
para determinar el constructor a utilizar para el nuevo array. A continuación, la nueva matriz se rellena con elementos. La copia siempre se realiza de forma superficial: el método nunca copia nada más allá de la matriz creada inicialmente. Los elementos de la(s) matriz(es) original(es) se copian en la nueva matriz de la siguiente manera:
- Objetos: la referencia al objeto se copia en la nueva matriz. Tanto la matriz original como la nueva hacen referencia al mismo objeto. Es decir, si se modifica un objeto referenciado, los cambios son visibles tanto en el array nuevo como en el original.
- Tipos primitivos como cadenas, números y booleanos (no objetos String, Number y Boolean): sus valores se copian en el nuevo array.
Otros métodos mutan el array sobre el que se ha llamado al método, en cuyo caso su valor de retorno difiere según el método: a veces una referencia al mismo array, a veces la longitud del nuevo array.
Métodos iterativos
Muchos métodos de matrices toman como argumento una función callback. La función callback se llama secuencialmente y como máximo una vez por cada elemento del array, y el valor de retorno de la función callback se utiliza para determinar el valor de retorno del método. Todos comparten la misma firma:
Donde callbackFn
toma tres argumentos:
element
: El elemento actual que se está procesando en el array.index
: El índice del elemento actual que se está procesando en la matriz.array
: El array sobre el que se ha llamado al método.
Lo que se espera que devuelva callbackFn
depende del método de array que fue llamado.
El argumento thisArg
(por defecto undefined
) se utilizará como el valor this
cuando se llame a callbackFn
. El valor this
observable en última instancia por callbackFn
se determina según las reglas habituales: si callbackFn
no es estricto, los valores this
primitivos se envuelven en objetos, y undefined/null
se sustituye por globalThis
. El argumento thisArg
es irrelevante para cualquier callbackFn
definido con una función de flecha, ya que las funciones de flecha no tienen su propio enlace this
.
Todos los métodos iterativos son copiadores y genéricos, aunque se comportan de forma diferente con ranuras vacías.
Métodos de array genéricos
Los métodos de array son siempre genéricos - no acceden a ningún dato interno del objeto array. Sólo acceden a los elementos del array a través de la propiedad length y a los elementos indexados. Esto significa que también pueden invocarse en objetos tipo array.
Normalización de la propiedad de longitud
La propiedad length
se convierte a un entero y luego se sujeta al rango entre 0 y . NaN
se convierte en 0, por lo que incluso cuando length
no está presente o es undefined
, se comporta como si tuviera valor 0.
Algunos métodos de array establecen la propiedad length del objeto array. Siempre establecen el valor después de la normalización, por lo que la longitud siempre termina como un entero.
Objetos array-like
El término objeto tipo array se refiere a cualquier objeto que no se lance durante el proceso de conversión de longitud descrito anteriormente. En la práctica, se espera que dicho objeto tenga realmente una propiedad length
y que tenga elementos indexados en el rango de 0 a . (Si no tiene todos los índices, será funcionalmente equivalente a un array disperso).
Muchos objetos DOM son del tipo array - por ejemplo, NodeList
y HTMLCollection
. El objeto arguments
también es un array-like. Puedes llamar a métodos de array en ellos incluso si ellos mismos no tienen estos métodos.