Le presentamos una traducción de un artículo de Thomas Lombart, que se publicó en medium.freecodecamp.org. La traducción se publica con permiso del autor.
Un ejemplo del uso del método reduce para reducir una matrizPermítanme hacer una declaración audaz: los bucles a menudo son inútiles y hacen que el código sea difícil de leer. Para iteraciones en matrices, búsqueda, clasificación de elementos y otras acciones similares, puede usar uno de los métodos a continuación.
A pesar de la efectividad, la mayoría de estos métodos aún son poco conocidos y no muy populares. Haré el trabajo duro por ti y hablaré sobre los más útiles. Lea este artículo como guía para los métodos de matriz de JavaScript.
Nota : Antes de comenzar, necesita saber una cosa: estoy sesgado hacia la programación funcional. Para evitar efectos secundarios, me esfuerzo por aplicar métodos que no modifiquen directamente la matriz original. No le estoy diciendo que se niegue a cambiar la matriz, pero vale la pena considerar que algunos métodos conducen a esto. Como resultado, aparecen efectos secundarios, cambios no deseados y, como resultado, errores.
Este artículo se publicó originalmente en
thomlom.dev , donde puede encontrar más material de desarrollo web.
Los fundamentos
Hay cuatro métodos que vale la pena saber si está trabajando con matrices. Estos son el operador de
map
,
filter
,
reduce
y
spread
. Son efectivos y útiles.
mapaA menudo utilizará el método de
map
. En general, cada vez que necesite cambiar los elementos de una matriz, considere esta opción.
Toma un parámetro: una función que se llama en cada elemento de la matriz y luego devuelve una
nueva matriz para que no pueda haber efectos secundarios.
const numbers = [1, 2, 3, 4] const numbersPlusOne = numbers.map(n => n + 1) console.log(numbersPlusOne)
También puede crear una nueva matriz que almacene solo una propiedad específica del objeto.
const allActivities = [ { title: 'My activity', coordinates: [50.123, 3.291] }, { title: 'Another activity', coordinates: [1.238, 4.292] } ] const allCoordinates = allActivities.map(activity => activity.coordinates) console.log(allCoordinates)
Entonces, recuerde: cuando necesite
cambiar una matriz, piense en usar el
mapa .
filtroEl nombre de este método habla por sí mismo: úselo cuando desee filtrar una matriz.
Al igual que
map
,
filter
toma como parámetro único una función que se llama en cada elemento de la matriz. Esta función debería devolver un valor booleano:
true
: si desea guardar el elemento en una matriz;false
: si no desea guardarlo.
Como resultado, tendrá la nueva matriz correcta con los elementos que desea dejar.
Por ejemplo, solo se pueden almacenar números impares en una matriz.
const numbers = [1, 2, 3, 4, 5, 6] const oddNumbers = numbers.filter(n => n % 2 !== 0) console.log(oddNumbers)
También puede usar el filtro para eliminar un elemento específico de la matriz.
const participants = [ { id: 'a3f47', username: 'john' }, { id: 'fek28', username: 'mary' }, { id: 'n3j44', username: 'sam' }, ] function removeParticipant(participants, id) { return participants.filter(participant => participant.id !== id) } console.log(removeParticipant(participants, 'a3f47'))
reducirEn mi opinión, este método es el más difícil de entender. Pero tan pronto como lo domines, tendrás muchas oportunidades.
Por lo general, el método
reduce
toma una matriz de valores y los concatena en un solo valor. Se necesitan dos parámetros, una función de devolución de llamada (que es el
reductor ) y un valor inicial opcional (que es el primer elemento de la matriz de forma predeterminada). La caja de cambios en sí toma cuatro parámetros:
- una batería que recoge los valores devueltos en la caja de cambios ;
- valor actual de la matriz;
- índice actual;
- la matriz para la que se llamó al método
reduce
.
Básicamente, usará solo los dos primeros parámetros: la batería y el valor actual.
Pero no profundicemos en la teoría y consideremos el ejemplo más común de aplicar
reduce
.
const numbers = [37, 12, 28, 4, 9] const total = numbers.reduce((total, n) => total + n) console.log(total)
En la primera iteración, el acumulador, que es la suma, toma el valor inicial 37. El valor devuelto es 37 + n, donde n = 12. Obtenemos 49.
Durante la segunda iteración, el acumulador es 49, el valor devuelto es 49 + 28 = 77. Y así sucesivamente.
El método de
reduce
es tan funcional que puede usarlo para construir muchos métodos de matriz como
map
o
filter
.
const map = (arr, fn) => { return arr.reduce((mappedArr, element) => { return [...mappedArr, fn(element)] }, []) } console.log(map([1, 2, 3, 4], n => n + 1))
Como regla general, asignamos el valor inicial
[]
al método de
reduce
: el acumulador. Para el
map
ejecutamos una función cuyo resultado se agrega al final de la batería utilizando
el operador de propagación (hablaremos de ello a continuación, no se preocupe). Para el
filter
haciendo casi lo mismo, solo ejecutamos la función de filtro en el elemento. Si es cierto, devolvemos la matriz
anterior . De lo contrario, agregue el elemento al final de la matriz.
Veamos un ejemplo más complejo: reduzca considerablemente la matriz
[1, 2, 3, [4, [[[5, [6, 7]]]], 8]]
a
[1, 2, 3, 4, 5, 6, 7, 8]
.
function flatDeep(arr) { return arr.reduce((flattenArray, element) => { return Array.isArray(element) ? [...flattenArray, ...flatDeep(element)] : [...flattenArray, element] }, []) } console.log(flatDeep([1, 2, 3, [4, [[[5, [6, 7]]]], 8]]))
Este ejemplo es muy similar al
map
, excepto que usamos recursividad aquí. No me detendré en la recursión en detalle, porque esto está más allá del alcance de nuestro tema, pero si desea saber más, vaya a este
excelente recurso .
Declaración de spread (ES2015)Estoy de acuerdo, este no es un método. Sin embargo, el operador de propagación ayuda a lograr diferentes objetivos cuando se trabaja con matrices. Puede aplicarlo para expandir los valores de una matriz en otra y luego hacer una copia o vincular varias matrices.
const numbers = [1, 2, 3] const numbersCopy = [...numbers] console.log(numbersCopy)
Nota : la declaración de propagación hace una
copia superficial de la matriz original. Pero, ¿qué significa "superficial"?
Dicha copia duplicará los elementos originales lo menos posible. Si tiene una matriz con números, cadenas o valores booleanos (
tipos primitivos ), no hay problemas y los valores están realmente duplicados. Sin embargo, las cosas son diferentes con los
objetos y las
matrices : solo se copia una
referencia al valor original. Por lo tanto, si realiza una copia superficial de la matriz, incluido el objeto, y cambia el objeto en la matriz copiada, también se cambiará en el original, ya que tienen la
misma referencia .
const arr = ['foo', 42, { name: 'Thomas' }] let copy = [...arr] copy[0] = 'bar' console.log(arr)
Entonces, si desea crear una copia real de una matriz que contenga un objeto o matrices, puede usar una función
lodash como
cloneDeep . Pero no te consideres obligado a hacer esto. Su objetivo es
descubrir cómo funciona todo bajo el capó .
Metodos utiles
A continuación encontrará otros métodos que también son útiles para conocer y que pueden ser útiles para resolver problemas como encontrar un elemento en una matriz, eliminar parte de una matriz y mucho más.
incluye (ES2015)¿Alguna vez ha usado
indexOf
para averiguar si hay un elemento en una matriz o no? Una forma terrible de verificar, ¿verdad?
Afortunadamente, el método
includes
la validación por nosotros. Establezca el parámetro para inclusiones, y buscará el elemento en la matriz.
const sports = ['football', 'archery', 'judo'] const hasFootball = sports.includes('football') console.log(hasFootball)
concatEl método concat se puede usar para fusionar dos o más matrices.
const numbers = [1, 2, 3] const otherNumbers = [4, 5, 6] const numbersConcatenated = numbers.concat(otherNumbers) console.log(numbersConcatenated)
por cadaSi desea realizar una acción para cada elemento de la matriz, puede usar el método
forEach
. Toma una función como parámetro, que a su vez también toma tres parámetros: valor actual, índice y matriz.
const numbers = [1, 2, 3, 4, 5] numbers.forEach(console.log)
indexOfEste método se utiliza para devolver el primer índice en el que se puede encontrar el elemento en la matriz. Además,
indexOf
menudo verifica la presencia de un elemento en una matriz. Honestamente, ahora lo uso con poca frecuencia.
const sports = ['football', 'archery', 'judo'] const judoIndex = sports.indexOf('judo') console.log(judoIndex)
encontrarEl método de
find
es similar al
filter
. Debe proporcionarle una función que pruebe cada elemento de la matriz. Sin embargo,
find
detiene los elementos de prueba tan pronto como encuentra uno que pasó la prueba. Este
no es
un filter
que itera sobre toda la matriz, independientemente de las circunstancias.
const users = [ { id: 'af35', name: 'john' }, { id: '6gbe', name: 'mary' }, { id: '932j', name: 'gary' }, ] const user = users.find(user => user.id === '6gbe') console.log(user)
Por lo tanto, utilice el método de
filter
cuando desee filtrar
toda la matriz y el método de
find
cuando esté seguro de que está buscando un elemento
único en la matriz.
findIndexEste método es casi lo mismo que
find
, pero devuelve el índice del primer elemento encontrado en lugar del elemento en sí.
const users = [ { id: 'af35', name: 'john' }, { id: '6gbe', name: 'mary' }, { id: '932j', name: 'gary' }, ] const user = users.findIndex(user => user.id === '6gbe') console.log(user)
Puede pensar que
findIndex
e
indexOf
son lo mismo. En realidad no El primer parámetro de
indexOf
es un valor primitivo (un valor booleano, número, cadena, valor o carácter indefinido), mientras que el primer parámetro
findIndex
es una función de devolución de llamada.
Por lo tanto, cuando necesite encontrar el índice de un elemento en una matriz de valores primitivos, puede trabajar con
indexOf
. Si tiene elementos más complejos, como objetos, use
findIndex
.
cortarCuando necesite formar parte de una matriz o copiar una matriz, puede consultar el método de
slice
. Pero tenga cuidado: al igual que el operador de propagación, la
slice
devuelve una
copia superficial .
const numbers = [1, 2, 3, 4, 5] const copy = numbers.slice()
Al comienzo del artículo, mencioné que los bucles a menudo son inútiles. Déjame mostrarte cómo deshacerte de ellos.
Suponga que desea devolver una cierta cantidad de mensajes de chat desde la API y solo necesita ver cinco de ellos. A continuación hay dos enfoques: uno con bucles, el otro con el método de
slice
.
algunosSi desea verificar si
al menos un elemento de la matriz pasa la prueba, puede usar
some
. Al igual que
map
,
filter
o
find
, el método
some
toma una función de devolución de llamada como el único parámetro, y luego devuelve
true
si al menos un elemento pasa la verificación, y
false
si no.
some
también son adecuados para trabajar con permisos.
const users = [ { id: 'fe34', permissions: ['read', 'write'], }, { id: 'a198', permissions: [], }, { id: '18aa', permissions: ['delete', 'read', 'write'], } ] const hasDeletePermission = users.some(user => user.permissions.includes('delete') ) console.log(hasDeletePermission)
cadaEste método es similar a
some
, excepto que verifica que
cada elemento (y
no uno ) coincida con la condición.
const users = [ { id: 'fe34', permissions: ['read', 'write'], }, { id: 'a198', permissions: [], }, { id: '18aa', permissions: ['delete', 'read', 'write'], } ] const hasAllReadPermission = users.every(user => user.permissions.includes('read') ) console.log(hasAllReadPermission)
plano (ES2019)Estos son métodos completamente nuevos en el mundo de JavaScript. Por lo general,
flat
crea una nueva matriz, conectando todos los elementos de una matriz anidada. Se necesita un parámetro: un número que indica cuánto desea reducir la dimensión de la matriz.
const numbers = [1, 2, [3, 4, [5, [6, 7]], [[[[8]]]]]] const numbersflattenOnce = numbers.flat() console.log(numbersflattenOnce)
flatMap (ES2019)¿Adivina qué hace este método? Apuesto a que entenderás un nombre.
Primero, ejecuta la función de mapeo para cada elemento, y luego reduce la matriz a la vez. Tan simple como eso!
const sentences = [ 'This is a sentence', 'This is another sentence', "I can't find any original phrases", ] const allWords = sentences.flatMap(sentence => sentence.split(' ')) console.log(allWords)
En este ejemplo, tiene muchas oraciones en la matriz y desea obtener todas las palabras. En lugar de usar el método de
map
y dividir todas las oraciones en palabras y luego acortar la matriz, puede usar
flatMap
.
Luego puede contar el número de palabras con la función
reduce
(esto no se aplica a
flatMap
, solo quiero mostrarle otro ejemplo del uso del método
reduce
).
const wordsCount = allWords.reduce((count, word) => { count[word] = count[word] ? count[word] + 1 : 1 return count }, {}) console.log(wordsCount)
El método
flatMap
también se usa a menudo en la programación reactiva. Puedes ver un ejemplo
aquí .
unirseSi necesita crear una cadena basada en elementos de matriz, el método de
join
es lo que necesita. Le permite crear una nueva línea conectando todos los elementos de la matriz, separados por el separador proporcionado.
Por ejemplo, usando
join
puede mostrar visualmente a todos los participantes en una actividad.
const participants = ['john', 'mary', 'gary'] const participantsFormatted = participants.join(', ') console.log(participantsFormatted)
Y este es un ejemplo más realista en el que primero puede filtrar a los participantes y obtener sus nombres.
const potentialParticipants = [ { id: 'k38i', name: 'john', age: 17 }, { id: 'baf3', name: 'mary', age: 13 }, { id: 'a111', name: 'gary', age: 24 }, { id: 'fx34', name: 'emma', age: 34 }, ] const participantsFormatted = potentialParticipants .filter(user => user.age > 18) .map(user => user.name) .join(', ') console.log(participantsFormatted)
deEste es un método
estático que crea una nueva matriz a partir de un objeto iterativo o similar a una matriz, como una cadena. Puede ser útil cuando trabaja con el modelo de objeto de documento.
const nodes = document.querySelectorAll('.todo-item')
¿Viste que usamos un tipo de matriz en lugar de una instancia de matriz? Es por eso que este método se llama estático.
Luego, puede divertirse con los nodos, por ejemplo, registrar oyentes de eventos para cada uno de ellos utilizando el método
forEach
.
todoItems.forEach(item => { item.addEventListener('click', function() { alert(`You clicked on ${item.innerHTML}`) }) })
Modificación de matriz que vale la pena conocer
Los siguientes son otros métodos estándar. Su diferencia es que modifican la matriz original. No hay nada de malo en el cambio, pero debe considerarlo cuando trabaje.
Si no desea modificar la matriz original mientras trabaja con estos métodos, haga una copia completa o de superficie por adelantado.
const arr = [1, 2, 3, 4, 5] const copy = [...arr]
ordenarSí,
sort
modifica la matriz original. De hecho, ordena los elementos de la matriz en su lugar. El método de ordenación predeterminado transforma todos los elementos en cadenas y los ordena en orden alfabético.
const names = ['john', 'mary', 'gary', 'anna'] names.sort() console.log(names)
Tenga cuidado: si, por ejemplo, cambió del lenguaje Python, entonces el método de
sort
al trabajar con una matriz de números no le dará el resultado deseado.
const numbers = [23, 12, 17, 187, 3, 90] numbers.sort() console.log(numbers)
¿Cómo, entonces, ordenar una matriz? El método de
sort
toma una función:
una función de comparación . Toma dos parámetros: el primer elemento (
) y el segundo elemento para la comparación (
b
). Una comparación entre estos dos elementos requiere que se devuelva un dígito:
- si el valor es negativo,
a
ordena antes que b
; - si el valor es positivo,
b
ordena antes que a
; - si el valor es 0, no hay cambio.
Entonces puedes ordenar los números.
const numbers = [23, 12, 17, 187, 3, 90] numbers.sort((a, b) => a - b) console.log(numbers)
O puede ordenar las fechas de la última.
const posts = [ { title: 'Create a Discord bot under 15 minutes', date: new Date(2018, 11, 26), }, { title: 'How to get better at writing CSS', date: new Date(2018, 06, 17) }, { title: 'JavaScript arrays', date: new Date() }, ] posts.sort((a, b) => a.date - b.date)
llenarEl método de
fill
modifica o llena todos los elementos de la matriz desde el índice inicial hasta el final con el valor especificado. Un ejemplo del excelente uso del
fill
es llenar una nueva matriz con datos iniciales.
revertirMe parece que el nombre del método explica completamente su esencia.
const numbers = [1, 2, 3, 4, 5] numbers.reverse() console.log(numbers)
popEste método elimina el último elemento de la matriz y lo devuelve.
const messages = ['Hello', 'Hey', 'How are you?', "I'm fine"] const lastMessage = messages.pop() console.log(messages)
Métodos que pueden ser reemplazados
En la última sección, encontrará métodos que modifican la matriz original y que son fáciles de encontrar una alternativa. No estoy diciendo que necesiten un descuento, solo quiero transmitirles que algunos métodos tienen efectos secundarios y pueden reemplazarse.
empujarEste método se usa con frecuencia. Le permite agregar uno o más elementos a la matriz, así como crear una nueva matriz basada en la anterior.
const todoItems = [1, 2, 3, 4, 5] const itemsIncremented = [] for (let i = 0; i < items.length; i++) { itemsIncremented.push(items[i] + 1) } console.log(itemsIncremented)
Si necesita construir una matriz sobre la base de otra, como en el método
itemsIncremented
, existen
map
adecuados,
filter
o
itemsIncremented
reduce
que ya nos son familiares. Por ejemplo, podemos tomar el
map
para hacer esto.
const itemsIncremented = todoItems.map(x => x + 1)
Y si desea usar
push
cuando necesita agregar un nuevo elemento, entonces el operador de propagación es útil.
const todos = ['Write an article', 'Proofreading'] console.log([...todos, 'Publish the article'])
empalmesplice
menudo se accede al
splice
para limpiar un elemento en un índice específico. Puede hacer lo mismo con el método de
filter
.
const months = ['January', 'February', 'March', 'April', ' May']
Puede preguntar: ¿qué pasa si necesito eliminar muchos elementos? Luego usa
slice
.
const months = ['January', 'February', 'March', 'April', ' May']
turnoEl método
shift
elimina el primer elemento de la matriz y lo devuelve. Para hacer esto en el estilo de la programación funcional, puede usar la declaración spread o rest.
const numbers = [1, 2, 3, 4, 5]
no cambiarEl método unshift le permite agregar uno o más elementos al comienzo de una matriz. Al igual que
shift
, puede hacer esto con el operador de propagación.
const numbers = [3, 4, 5]
TL; DR
- Cuando desee realizar algunas operaciones con una matriz, no use el bucle for y no reinvente la rueda, porque lo más probable es que exista un método de lo anterior que pueda hacer lo que necesita.
- La mayoría de las veces usará el
map
, el filter
, reduce
métodos de reduce
y el operador de propagación: estas son herramientas importantes para cualquier desarrollador. - También hay muchos métodos de matriz que sería bueno saber:
slice
, some
, flatMap
, etc. flatMap
y aplique si es necesario. - Los efectos secundarios pueden conducir a cambios no deseados. Tenga en cuenta que algunos métodos modifican su matriz original.
- El método de
slice
y el operador de propagación hacen copias superficiales. Como resultado, los objetos y las submatrices tendrán los mismos enlaces; también vale la pena tenerlo en cuenta. - Los métodos antiguos que modifican la matriz se pueden reemplazar por otros nuevos. Tú decides qué hacer.
Ahora ya sabe todo lo que debe saber sobre las matrices de JavaScript. Si te gustó
este artículo , haz clic en el botón "Pat" (hasta 50 veces, si quieres :-)) y compártelo. ¡Y siéntase libre de compartir sus impresiones en los comentarios!