Guía de JavaScript, parte 5: matrices y bucles

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) //   ,   6 ,  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) //[ 1, 2, 3 ] const first = a[0] console.log(first) //1 a[0] = 4 console.log(a) //[ 4, 2, 3 ] 

No se recomienda el constructor de matrices para declarar matrices.

 const a = new Array() //  const a = new Array(1, 2, 3) //  

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)) //true console.log(b.every(test)) //false 

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) //[ 1, 2, 3 ] console.log(doubleA) //[ 2, 4, 6 ] 

▍ 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) //24 // 1: 1 * 1 = 1 // 2: 1 * 2 = 2 // 3: 2 * 3 = 6 // 4: 6 * 4 = 24 

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)) //1 //2 //3 

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) } //1 //2 //3 

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]) } //1 //2 //3 

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) //1 console.log(it.next().value) //2 console.log(it.next().value) //3 

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) //[0, 1] console.log(it.next().value) //[1, 2] console.log(it.next().value) //[2, 3] 

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) //0 console.log(it.next().value) //1 console.log(it.next().value) //2 

▍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) //    2     a.splice(3, 2) //    2 ,    3 

▍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) //[ 1, 2, 'a', 'b', 6 ] 

▍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) //[ 1, 2, 3, 4 ] 

▍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)) //4 console.log(a.indexOf(23)) //-1 

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)) //7 console.log(a.lastIndexOf(23)) //-1 

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)) //[ 5, 6, 7, 8, 9 ] console.log(a.slice(3,7)) //[ 4, 5, 6, 7 ] 

▍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) //[ 1, 10, 11, 2, 3 ] const b = [1, 'a', 'Z', 3, 2, 11] b.sort() console.log(b) //[ 1, 11, 2, 3, 'Z', '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)) //[ 1, 2, 3, 10, 11 ] console.log(a.sort((a, b) => b - a)) //[ 11, 10, 3, 2, 1 ] 

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()) //1,10,3,2,11 console.log(a.join()) //1,10,3,2,11 console.log(a.join(', ')) //1, 10, 3, 2, 11 

▍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) //[ 'a', ' ', 's', 't', 'r', 'i', 'n', 'g' ] 

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) // [ 1, 10, 3, 2, 11 ] 

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) //[ 3, 4, 5, 4, 5 ] 

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]) //,     console.log(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) // console.log(index) // }) //     ,      list.forEach(item => 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]) // console.log(i) // i = i + 1 } while (i < list.length) 

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]) // console.log(i) // i = i + 1 } 

▍ 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) //  console.log(object[property]) //  } 

▍ Ciclo para ... de


El ciclo for...of combina la conveniencia del ciclo forEach y la capacidad de interrumpir su funcionamiento utilizando herramientas regulares.

 //  for (const value of ['a', 'b', 'c']) { console.log(value) // } //       `entries()` for (const [index, value] of ['a', 'b', 'c'].entries()) { console.log(index) // console.log(value) // } 

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?

Source: https://habr.com/ru/post/es430380/


All Articles