Hoy, en la quinta parte de la traducción del curso de JavaScript, hablaremos sobre matrices y bucles. Las matrices se utilizan para resolver muchos problemas. A menudo trabaja con matrices usando bucles.
→
Parte 1: primer programa, características del lenguaje, estándares→
Parte 2: estilo de código y estructura del programa→
Parte 3: variables, tipos de datos, expresiones, objetos.→
Parte 4: funciones→
Parte 5: matrices y bucles→
Parte 6: excepciones, punto y coma, literales comodín→
Parte 7: modo estricto, esta palabra clave, eventos, módulos, cálculos matemáticos→
Parte 8: Descripción general de las características de ES6→
Parte 9: Descripción general de los estándares ES7, ES8 y ES9
Matrices
Las matrices, objetos de tipo
Array
, evolucionan junto con otros mecanismos del lenguaje. Son listas de valores numerados.
El primer elemento de la matriz tiene un índice (clave) de 0; este enfoque se utiliza en muchos lenguajes de programación.
En esta sección consideraremos métodos modernos para trabajar con matrices.
▍Inicialización de matrices
Aquí hay algunas formas de inicializar matrices.
const a = [] const a = [1, 2, 3] const a = Array.of(1, 2, 3) const a = Array(6).fill(1)
Para acceder a un elemento individual de la matriz, utilice una construcción que consta de corchetes que contengan el índice del elemento de la matriz. Los elementos de la matriz pueden leerse o escribirse.
const a = [1, 2, 3] console.log(a)
No se recomienda el constructor de matrices para declarar matrices.
const a = new Array()
Este método solo se debe utilizar al declarar
matrices escritas .
▍ Obtener la longitud de la matriz
Para averiguar la longitud de una matriz, debe hacer referencia a su propiedad de
length
.
const l = a.length
▍Verificación de una matriz utilizando el método every ()
El método de matriz
every()
se puede utilizar para organizar la verificación de todos sus elementos utilizando una determinada condición. Si todos los elementos de la matriz cumplen la condición, la función devolverá
true
, de lo contrario, devolverá
false
.
A este método se le pasa una función que toma los argumentos
currentValue
(elemento de matriz actual),
index
(índice del elemento de matriz actual) y
array
(la matriz misma). También puede tomar un valor opcional, usado como
this
cuando se ejecuta la función que se le pasa.
Por ejemplo, verifique si los valores de todos los elementos de la matriz son mayores que 10.
const a = [11, 12, 13] const b = [5, 6, 25] const test = el => el > 10 console.log(a.every(test))
Aquí, en la función
test()
, solo estamos interesados en el primer argumento que se le pasa, por lo que lo declaramos, especificando solo
el
parámetro el, en el que caerá el valor correspondiente.
▍Verificación de una matriz utilizando el método some ()
Este método es muy similar al método
every()
, pero devuelve
true
si al menos uno de los elementos de la matriz cumple la condición especificada por la función que se le pasa.
▍Cree una matriz basada en una matriz existente usando el método map ()
El método
map()
de matrices le permite iterar sobre matrices, aplicando una función que convierte el elemento en cada elemento pasado a este método y crea nuevas matrices a partir de los valores recibidos. Aquí, por ejemplo, es cómo obtener una nueva matriz que es el resultado de multiplicar todos los elementos de la matriz original por 2.
const a = [1, 2, 3] const double = el => el * 2 const doubleA = a.map(double) console.log(a)
▍ Filtrar una matriz usando el método filter ()
El método
filter()
es similar al método
map()
, pero le permite crear nuevas matrices que contienen solo aquellos elementos de las matrices originales que satisfacen la condición especificada por el método
filter()
pasado a la función.
▍ método reduce ()
El método
reduce()
permite aplicar una función determinada al acumulador y a cada valor de la matriz, reduciendo la matriz a un solo valor (este valor puede tener un tipo primitivo o un objeto). Este método toma una función de conversión y un valor de batería inicial opcional. Considera un ejemplo.
const a = [1, 2, 3, 4].reduce((accumulator, currentValue, currentIndex, array) => { return accumulator * currentValue }, 1) console.log(a)
Aquí estamos buscando el producto de todos los elementos de la matriz descritos usando un literal, estableciendo el valor inicial del acumulador 1.
▍ Enumerar una matriz usando el método forEach ()
El método
forEach()
de las matrices se puede utilizar para iterar sobre los valores de las matrices y realizar ciertas acciones en ellas, especificadas por la función que se pasa al método. Por ejemplo, mostramos, uno a la vez, los elementos de la matriz en la consola.
const a = [1, 2, 3] a.forEach(el => console.log(el))
Si necesita detener o interrumpir el ciclo al iterar sobre una matriz, cuando use
forEach()
tendrá que lanzar una excepción. Por lo tanto, si en el curso de la resolución de un determinado problema puede ser necesario interrumpir el ciclo, es mejor elegir otra forma de iterar sobre los elementos de la matriz.
▍Seleccionar una matriz usando el operador for ... of
El
for...of
operador apareció en el estándar ES6. Le permite iterar sobre objetos iterables (incluidas las matrices). Aquí se explica cómo usarlo.
const a = [1, 2, 3] for (let v of a) { console.log(v) }
En cada iteración del bucle, el siguiente elemento de la matriz
a
ingresa a la variable
v
.
▍ Enumerar una matriz usando la instrucción for
La instrucción
for
permite organizar bucles, que, en particular, también se pueden usar para iterar sobre (o inicializar) matrices accediendo a sus elementos por índice. Típicamente, el índice del siguiente elemento se obtiene usando un contador de bucle.
const a = [1, 2, 3] for (let i = 0; i < a.length; i += 1) { console.log(a[i]) }
Si, durante la ejecución del bucle, necesita omitir su iteración, puede usar el comando
continue
. Para finalizar prematuramente el ciclo, puede usar el comando
break
. Si usa el comando
return
en un bucle, por ejemplo, ubicado en una determinada función, el bucle y la función finalizarán, y el valor devuelto con
return
irá a donde se llamó la función.
▍ Método @@ iterator
Este método apareció en el estándar ES6. Le permite obtener el llamado "iterador de un objeto", un objeto que en este caso le permite organizar una iteración de elementos de la matriz. Se puede obtener un iterador de matriz utilizando el símbolo (tales símbolos se denominan "símbolos conocidos")
Symbol.iterator
. Después de recibir el iterador, puede acceder a su método
next()
, que, con cada llamada, devuelve una estructura de datos que contiene el siguiente elemento de la matriz.
const a = [1, 2, 3] let it = a[Symbol.iterator]() console.log(it.next().value)
Si llama al método
next()
después de alcanzar el último elemento de la matriz, devolverá, como el valor del elemento,
undefined
. El objeto devuelto por el método
next()
contiene el
value
y las propiedades
done
. La propiedad
done
evalúa como
false
hasta que se alcanza el último elemento de la matriz. En nuestro caso, si lo llamamos.next
it.next()
por cuarta vez, devolverá el objeto
{ value: undefined, done: true }
, mientras que en las tres llamadas anteriores este objeto se vería como
{ value: , done: false }
.
El método de matriz de
entries()
devuelve un iterador que le permite iterar sobre los pares clave-valor de la matriz.
const a = [1, 2, 3] let it = a.entries() console.log(it.next().value)
El método
keys()
permite iterar sobre las claves de una matriz.
const a = [1, 2, 3] let it = a.keys() console.log(it.next().value)
▍Adición de elementos al final de una matriz
Para agregar elementos al final de la matriz, use el método
push()
.
a.push(4)
▍Agregar elementos al comienzo de la matriz
Para agregar elementos al comienzo de la matriz, use el método
unshift()
.
a.unshift(0) a.unshift(-2, -1)
▍Eliminar elementos de la matriz
Puede eliminar un elemento del final de la matriz mientras devuelve este elemento utilizando el método
pop()
.
a.pop()
Del mismo modo, utilizando el método
shift()
, puede eliminar un elemento desde el principio de la matriz.
a.shift()
Lo mismo, pero ya indicando la posición de la eliminación de elementos y su número, se realiza utilizando el método
splice()
.
a.splice(0, 2)
▍Eliminar elementos de matriz e insertar otros elementos en su lugar
Para utilizar alguna operación para eliminar algunos elementos de la matriz e insertar otros elementos, se utiliza el método familiar
splice()
.
Por ejemplo, aquí eliminamos 3 elementos de la matriz comenzando en el índice 2, después de lo cual agregamos otros dos elementos al mismo lugar:
const a = [1, 2, 3, 4, 5, 6] a.splice(2, 3, 'a', 'b') console.log(a)
▍Combinar múltiples matrices
Para combinar varias matrices, puede usar el método
concat()
, que devuelve una nueva matriz.
const a = [1, 2] const b = [3, 4] const c = a.concat(b) console.log(c)
▍Encontrar elementos en una matriz
En el estándar ES5, ha aparecido el método
indexOf()
, que devuelve el índice de la primera aparición del elemento de matriz deseado. Si el elemento no se puede encontrar en la matriz, se devuelve
-1
.
const a = [1, 2, 3, 4, 5, 6, 7, 5, 8] console.log(a.indexOf(5))
El método
lastIndexOf()
devuelve el índice de la última aparición del elemento en la matriz, o
-1
si no se encuentra el elemento.
const a = [1, 2, 3, 4, 5, 6, 7, 5, 8] console.log(a.lastIndexOf(5))
En ES6, apareció el método
find()
de matrices, que realiza una búsqueda de matrices utilizando la función que se le pasa. Si la función devuelve
true
, el método devuelve el valor del primer elemento encontrado. Si no se puede encontrar el elemento, la función volverá
undefined
.
Su uso puede verse de la siguiente manera.
a.find(x => x.id === my_id)
Aquí, en una matriz que contiene objetos, se busca un elemento cuya propiedad de
id
igual a la especificada.
El método
findIndex()
es similar a
find()
, pero devuelve el índice del elemento encontrado o
undefined
.
En ES7, apareció el método
includes()
, que le permite verificar la presencia de cierto elemento en la matriz. Devuelve
true
o
false
, encontrando o no encontrando un elemento de interés para el programador.
a.includes(value)
Con este método, es posible verificar la presencia de algún elemento, no toda la matriz, sino solo una parte, comenzando con el índice especificado cuando se llamó a este método. El índice se especifica utilizando el segundo parámetro opcional de este método.
a.includes(value, i)
▍ Obtener un fragmento de una matriz
Para obtener una copia de algún fragmento de la matriz como una nueva matriz, puede usar el método
slice()
. Si se llama a este método sin argumentos, la matriz devuelta será una copia completa del original. Se necesitan dos parámetros opcionales. El primero establece el índice inicial del fragmento, el segundo establece el final. Si no se especifica el índice final, la matriz se copia desde el índice inicial especificado hasta el final.
const a = [1, 2, 3, 4, 5, 6, 7, 8, 9] console.log(a.slice(4))
▍Ordenador de clasificación
Para organizar la ordenación de los elementos de la matriz en orden alfabético (
0-9A-Za-z
), se utiliza el método
sort()
sin pasarle argumentos.
const a = [1, 2, 3, 10, 11] a.sort() console.log(a)
Puede pasar una función a este método que establece el orden de clasificación. La función acepta, para la comparación de dos elementos, los parámetros
a
y
b
. Devuelve un número negativo si
a
menor que
b
según algún criterio, 0 si son iguales y un número positivo si
a
mayor que
b
. Al escribir una función similar para ordenar matrices numéricas, puede devolver el resultado de restar
b
. Por lo tanto, devolver el resultado de evaluar la expresión
a - b
significa ordenar la matriz en orden ascendente, devolviendo el resultado de evaluar la expresión
b - a
ordenará la matriz en orden descendente.
const a = [1, 10, 3, 2, 11] console.log(a.sort((a, b) => a - b))
Para invertir la secuencia de elementos de la matriz, puede usar el método
reverse()
. Al igual que
sort()
, modifica la matriz para la que se llama.
▍Obtener una representación de cadena de una matriz
Para obtener una representación de cadena de una matriz, puede usar su método
toString()
.
a.toString()
El método
join()
da un resultado similar, llamado sin argumentos.
a.join()
Para ello, como argumento, puede pasar los elementos separadores.
const a = [1, 10, 3, 2, 11] console.log(a.toString())
▍Creando copias de matrices
Para crear una copia de la matriz copiando los valores de la matriz original en la nueva matriz, puede usar el método
Array.from()
. También es adecuado para crear matrices a partir de objetos similares a matrices (a partir de cadenas, por ejemplo).
const a = 'a string' const b = Array.from(a) console.log(b)
El método
Array.of()
también se puede utilizar para copiar matrices, así como para "ensamblar" matrices de varios elementos. Por ejemplo, para copiar los elementos de una matriz a otra, puede usar la siguiente construcción.
const a = [1, 10, 3, 2, 11] const b = Array.of(...a) console.log(b)
El método
copyWithin()
se usa para copiar los elementos de la matriz en un lugar determinado de esta matriz. Su primer argumento especifica el índice inicial de la posición de destino, el segundo el índice inicial de la posición de la fuente del elemento, y el tercer parámetro, opcional, indica el índice final de la posición de la fuente del elemento. Si no lo especifica, todo se copiará en la ubicación especificada de la matriz, comenzando desde el índice inicial de la posición de origen hasta el final de la matriz.
const a = [1, 2, 3, 4, 5] a.copyWithin(0, 2) console.log(a)
Ciclos
Hablando de las matrices anteriores, ya hemos encontrado algunas formas de organizar bucles. Sin embargo, los bucles en JavaScript se usan no solo para trabajar con matrices, y hemos considerado lejos de todos sus tipos. Por lo tanto, ahora dedicaremos algo de tiempo a discutir diferentes formas de organizar bucles en JavaScript y hablar sobre sus características.
▍ para bucle
Considere un ejemplo de aplicación de este ciclo.
const list = ['a', 'b', 'c'] for (let i = 0; i < list.length; i++) { console.log(list[i])
Como ya se mencionó, puede interrumpir la ejecución de dicho ciclo usando el comando
break
, y puede omitir la iteración actual e ir directamente a la siguiente usando el comando
continue
.
▍ para cada ciclo
También discutimos este ciclo. Aquí hay un ejemplo de iterar sobre una matriz usándolo.
const list = ['a', 'b', 'c'] list.forEach((item, index) => { console.log(item)
Recuerde que para interrumpir dicho ciclo, es necesario lanzar una excepción, es decir, si necesita interrumpirlo cuando usa un ciclo, es mejor elegir otro ciclo.
▍ Hacer ... mientras bucle
Este es el llamado "ciclo posterior a la condición". Dicho ciclo se ejecutará al menos una vez antes de verificar la condición para finalizar el ciclo.
const list = ['a', 'b', 'c'] let i = 0 do { console.log(list[i])
Se puede interrumpir usando el comando
break
, puede continuar con su próxima iteración con el comando
continue
.
▍ while loop
Este es el llamado "ciclo preacondicionado". Si, a la entrada del ciclo, la condición para continuar el ciclo es falsa, no se ejecutará ni una sola vez.
const list = ['a', 'b', 'c'] let i = 0 while (i < list.length) { console.log(list[i])
▍ para ... en bucle
Este bucle le permite iterar sobre todas las propiedades enumeradas de un objeto por sus nombres.
let object = {a: 1, b: 2, c: 'three'} for (let property in object) { console.log(property)
▍ Ciclo para ... de
El ciclo
for...of
combina la conveniencia del ciclo
forEach
y la capacidad de interrumpir su funcionamiento utilizando herramientas regulares.
Tenga en cuenta que aquí, en el encabezado del bucle, se usa la palabra clave
const
y no, como es de esperar,
let
. Si no es necesario reasignar las variables dentro del bloque de bucle, entonces
const
es muy adecuado para nosotros.
Si comparamos los
for...in
y
for...of
bucles, resulta que
for...in
itera sobre los nombres de las propiedades y
for...of
- valores de las propiedades.
Bucles y alcances
Con bucles y ámbitos variables, hay una característica de JavaScript que puede causarle problemas al desarrollador. Para tratar estos problemas,
let
bucles, los ámbitos y las palabras clave
var
y
let
.
Considera un ejemplo.
const operations = [] for (var i = 0; i < 5; i++) { operations.push(() => { console.log(i) }) } for (const operation of operations) { operation() }
El bucle realiza 5 iteraciones, en cada una de las cuales se agrega una nueva función a la matriz de
operations
. Esta función muestra en la consola el valor del contador de bucle -
i
. Después de agregar las funciones a la matriz, iteramos sobre esta matriz y llamamos a las funciones que son sus elementos.
Al ejecutar dicho código, puede esperar el resultado que se muestra a continuación.
0 1 2 3 4
Pero, de hecho, infiere lo siguiente.
5 5 5 5 5
¿Por qué es esto así? La cuestión es que, como contador de bucle, usamos una variable declarada con la palabra clave
var
.
Como las declaraciones de tales variables van al principio del alcance, el código anterior es similar al siguiente.
var i; const operations = [] for (i = 0; i < 5; i++) { operations.push(() => { console.log(i) }) } for (const operation of operations) { operation() }
Como resultado, resulta que en el ciclo
for...of
, en el que iteramos sobre la matriz, la variable
i
todavía es visible, es 5, como resultado, haciendo referencia a
i
en todas las funciones, imprimimos el número 5.
¿Cómo cambiar el comportamiento del programa para que haga lo que se espera de él?
La solución más simple a este problema es usar la palabra clave
let
. Como ya dijimos, apareció en ES6, su uso le permite deshacerse de algunas rarezas características de la
var
.
En particular, en el ejemplo anterior, es suficiente cambiar
var
para
let
todo funcione como debería.
const operations = [] for (let i = 0; i < 5; i++) { operations.push(() => { console.log(i) }) } for (const operation of operations) { operation() }
Ahora, en cada iteración del ciclo, cada función agregada a la matriz de
operations
obtiene su propia copia de
i
. Recuerde que en esta situación no puede usar la palabra clave
const
, ya que el valor de
i
en el bucle cambia.
Otra forma de resolver este problema, que a menudo se usaba antes del estándar ES6, cuando la palabra clave
let
no estaba allí, era usar IIFE.
Con este enfoque, el valor de
i
almacena en el cierre, y la función devuelta por IIFE y que tiene acceso al cierre entra en la matriz. Esta función se puede realizar cuando sea necesario. Así es como se ve.
const operations = [] for (var i = 0; i < 5; i++) { operations.push(((j) => { return () => console.log(j) })(i)) } for (const operation of operations) { operation() }
Resumen
Hoy hablamos de matrices y bucles en JavaScript. El tema de nuestro próximo artículo es el manejo de excepciones, los patrones de uso de punto y coma y los literales de plantilla.
Estimados lectores! ¿Qué métodos para trabajar con matrices en JavaScript utiliza con más frecuencia?
