map, filter y flatMap en JavaScript | Nicolás Garzón
map, filter y flatMap crean arrays nuevos a partir de una colección existente.
Cada uno responde una pregunta diferente:
Texto
Copiar map → ¿Cómo transformo cada elemento?
filter → ¿Cuáles elementos conservo?
flatMap → ¿Cómo transformo y produzco cero, uno o varios elementos?
map llama un callback por cada posición existente y utiliza su retorno como elemento del nuevo array.
JavaScript
Copiar const prices = [ 10 , 20 , 30 ] ;
const pricesWithTax = prices. map (
( price ) => price * 1.19 ,
) ; JavaScript
Copiar prices;
pricesWithTax; No modifica el array original, pero los valores retornados pueden seguir compartiendo referencias.
JavaScript
Copiar const result = values. map (
( value, index, array ) => {
return transform ( value) ;
} ,
) ;
Valor actual.
Índice.
Array recorrido.
No necesitas declarar parámetros que no utilices.
JavaScript
Copiar const names = users. map ( ( user ) => user. name) ; JavaScript
Copiar const values = [ 1 , 2 , 3 ] ;
const doubled = values. map (
( value ) => value * 2 ,
) ;
Si el callback retorna undefined, esa posición existe con valor undefined.
JavaScript
Copiar const result = values. map ( ( value ) => {
if ( value > 1 ) {
return value;
}
} ) ;
Para descartar elementos utiliza filter.
JavaScript
Copiar products. map ( ( product ) => {
console. log ( product. name) ;
} ) ; El array retornado se ignora. Un for...of o forEach comunica mejor un efecto.
JavaScript
Copiar for ( const product of products) {
console. log ( product. name) ;
} JavaScript
Copiar [ "10" , "10" , "10" ] . map ( parseInt) ; JavaScript
Copiar [ 10 , NaN , 2 ] map pasa valor e índice; parseInt interpreta el segundo argumento como radix.
JavaScript
Copiar parseInt ( "10" , 0 ) ;
parseInt ( "10" , 1 ) ;
parseInt ( "10" , 2 ) ; Usa un callback que exprese el contrato.
JavaScript
Copiar [ "10" , "10" , "10" ] . map (
( value ) => Number. parseInt ( value, 10 ) ,
) ; O Number cuando quieres convertir el string completo.
JavaScript
Copiar [ "10" , "20" ] . map ( Number) ; JavaScript
Copiar const cards = products. map ( ( product ) => ( {
id : product. id,
title : product. name,
priceLabel : formatCurrency ( product. price) ,
} ) ) ; Cada retorno es un objeto nuevo. Las propiedades anidadas copiadas continúan compartiendo referencias salvo que también se transformen.
JavaScript
Copiar const result = products. map ( ( product ) => {
product. isVisible = true ;
return product;
} ) ; El array exterior es nuevo, pero los objetos originales fueron modificados.
Una transformación sin esa mutación:
JavaScript
Copiar const result = products. map ( ( product ) => ( {
... product,
isVisible : true ,
} ) ) ; La copia sigue siendo superficial.
filter conserva los elementos cuyo callback retorna un valor truthy.
JavaScript
Copiar const activeProducts = products. filter (
( product ) => product. isActive,
) ; El resultado puede contener desde cero hasta todos los elementos.
JavaScript
Copiar [ 1 , 2 , 3 , 4 ] . filter (
( number ) => number % 2 === 0 ,
) ;
JavaScript
Copiar const products = [
{ name : "Keyboard" , active : true } ,
] ;
const active = products. filter (
( product ) => product. active,
) ;
active[ 0 ] === products[ 0 ] ; filter selecciona; no clona elementos.
JavaScript
Copiar const values = [ 0 , 1 , "" , "Hello" , null ] ;
const compact = values. filter ( Boolean) ;
Es una forma breve de retirar valores falsy, pero también elimina valores legítimos como 0, false y "".
Cuando la regla sea específica, escríbela.
JavaScript
Copiar const withoutNullish = values. filter (
( value ) => value != null ,
) ; flat aplana arrays anidados hasta una profundidad.
JavaScript
Copiar const values = [ [ 1 , 2 ] , [ 3 , 4 ] ] ;
values. flat ( ) ; JavaScript
Copiar const values = [ 1 , [ 2 , [ 3 ] ] ] ;
values. flat ( ) ;
values. flat ( 2 ) ; Infinity aplana todas las capas encontradas, pero puede ocultar una estructura incorrecta y tener un costo alto.
flatMap equivale conceptualmente a mapear y después aplanar una capa.
JavaScript
Copiar const result = values. flatMap ( mapper) ; Puede producir un elemento:
JavaScript
Copiar const names = users. flatMap (
( user ) => user. name,
) ; JavaScript
Copiar const words = sentences. flatMap (
( sentence ) => sentence. split ( " " ) ,
) ; JavaScript
Copiar const activeIds = products. flatMap (
( product ) =>
product. isActive ? [ product. id] : [ ] ,
) ; Eso permite transformar y filtrar en un solo recorrido.
JavaScript
Copiar [ 1 , 2 ] . flatMap (
( value ) => [ [ value] ] ,
) ;
El callback retornó dos capas y solo se retiró una.
JavaScript
Copiar const values = [ 1 , 2 ] . map (
( value ) => [ value, value * 10 ] ,
) ;
JavaScript
Copiar const values = [ 1 , 2 ] . flatMap (
( value ) => [ value, value * 10 ] ,
) ;
JavaScript
Copiar const visibleCards = products
. filter ( ( product ) => product. isActive)
. map ( ( product ) => ( {
id : product. id,
title : product. name,
} ) ) ; Filtrar antes evita transformar elementos que serán descartados.
JavaScript
Copiar products
. map ( expensiveTransformation)
. filter ( isVisible) ; Puede hacer trabajo innecesario si la condición estaba disponible desde el inicio.
Cada map o filter crea un array. En datos normales esto suele favorecer claridad.
En colecciones enormes o rutas críticas:
Mide antes de optimizar.
Considera un solo bucle cuando evita intermedios relevantes.
Usa iteradores cuando necesitas evaluación perezosa.
No combines operaciones únicamente para reducir líneas.
Código claro con dos pasos nombrados puede ser mejor que una cadena difícil de leer.
JavaScript
Copiar const results = products. map ( async ( product ) => {
return saveProduct ( product) ;
} ) ; results es un array de promesas, no de valores resueltos.
JavaScript
Copiar const savedProducts = await Promise. all ( results) ; filter no espera predicados asíncronos.
JavaScript
Copiar products. filter ( async ( ) => false ) ; Cada promesa es truthy, así que probablemente conservará todos los elementos.
Para condiciones asíncronas, primero resuelve resultados y después filtra, o usa un recorrido explícito.
map, filter y flatMap omiten holes.
JavaScript
Copiar const sparse = new Array ( 3 ) ;
const mapped = sparse. map ( ( ) => 1 ) ;
Object. hasOwn ( mapped, 0 ) ; map conserva la estructura dispersa; filter crea un array denso con los valores visitados.
Este comportamiento se profundiza en Arrays dispersos y casos límite .
JavaScript
Copiar const options = products
. filter (
( product ) =>
product. isActive && product. stock > 0 ,
)
. map ( ( product ) => ( {
value : product. id,
label : ` ${ product. name} · ${ product. stock} ` ,
} ) ) ; La colección original no cambia y el resultado contiene únicamente la forma que necesita la interfaz.
Usar map cuando el retorno no se utiliza.
Intentar filtrar retornando undefined desde map.
Creer que filter clona objetos.
Mutar elementos dentro de una transformación que parece inmutable.
Usar filter(Boolean) cuando 0 o false son válidos.
Pasar parseInt directamente a map.
Esperar que callbacks async sean esperados automáticamente.
Creer que flatMap aplana cualquier profundidad.
Encadenar demasiadas operaciones sin cuidar la lectura.
map produce un valor por posición visitada.
filter conserva referencias cuyo predicado es truthy.
flatMap transforma y aplana una sola capa.
Ninguno modifica el array exterior original.
No crean copias profundas de los elementos.
map no es la herramienta para efectos ignorando su retorno.
Callbacks async producen promesas; el método no las espera.
El orden de una cadena afecta trabajo y significado.
¿Qué problema tiene este código?
JavaScript
Copiar const visible = products. filter ( async ( product ) => {
return canViewProduct ( product) ;
} ) ; Respuesta filter no espera el resultado asíncrono. Cada callback retorna una promesa, que es truthy, por lo que puede conservar todos los productos. Debe resolverse la condición antes de filtrar o utilizarse un recorrido asíncrono explícito.
find, includes, some y every estudia búsqueda, pertenencia y validaciones que pueden detenerse antes de recorrer toda la colección.