Aún no tienes acceso a esta clase

Crea una cuenta y continúa viendo este curso

Map Reloaded

6/27
Recursos

Aportes 35

Preguntas 2

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesión.

Esta clase es otro nivel. Yo hubiera pensado que map mutó mi array, pero resulta que no, que solo lo dejó en la referencia de la memoria. Y la técnica para agregar sin cambiar la referencia vale su peso en oro. Por cosas así es que pago por Platzi.

Aquí va el array de objetos para el ejercicio 😃

const orders = [
  {
    customerName: "Nicolas",
    total: 60,
    delivered: true,
  },
  {
    customerName: "Zulema",
    total: 120,
    delivered: false,
  },
  {
    customerName: "Santiago",
    total: 180,
    delivered: true,
  },
  {
    customerName: "Valentina",
    total: 240,
    delivered: true,
  },
];

Usos comunes o clásicos de map() sobre los arrays:

  • Limpiar datos, seleccionar datos dentro de un array y devolverlos para su utilización en futuras acciones.
  • Añadir un nuevo elemento, modificar agregando un nuevo dato al objeto pero sin modificar el array original.

.
Tener en cuenta que cuando trabajamos con objetos y map() y retornamos el mismo objeto estamos copiando la referencia en memoria que tiene el objeto original que le aplicamos el map() (esto lo vimos en la clase de mutable vs inmutable, te dejo una lectura: https://platzi.com/tutoriales/1642-javascript-profesional/4559-estructuras-de-datos-inmutables/). Esto provoca que como estamos modificando la referencia en memoria, el array original también sea modificado. Entonces en conclusión, por más que map() sea inmutable en este punto estamos copiando la referencia en memoria y por eso hace el cambio en el original.

// Estamos retornando el objeto
// por ende se copia la refencia en memoria
const rta = orders.map(item => {
    item.tax = .19
    return item;
})

Para evitarlo, y poder realizar una copia y evitar la referencia en memoria, utilizamos el spread operator de ES6 (https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Operators/Spread_syntax), donde generamos un nuevo objeto con los valores del objeto original y luego agregamos el nuevo valor que nos interesa.

const rta = orders.map(item => {
    // retornamos un nuevo objeto 
    //pero evitamos hacer ref. en memoria
    return {
        ...item,
        tax: .19,
    }
})

Y esas líneas se pueden reducir aún más 😃:

const withTax = orders.map(order => ({ ...order, tax: .17 }))

Para entender por qué se modifica el array cuando trabajamos con objetos les recomiendo la clase donde JuanDC nos explica como funciona la memoria en JS:
https://platzi.com/clases/2419-javascript-poo-intermedio/39811-como-funciona-la-memoria-en-javascript/

Faltó como modificar una propiedad en otra referencia en memoria sin modificar el original:

// Modificar el original en otro objeto en memoria
const resp4 = orders.map(item => {
    return {
        ...item,
        total: item.total + 5,
    };
});
console.log('Resp4:', resp4);
console.log('Original:', orders);

Tener cuidado con el spread operator. si el objeto contiene otros objetos, se seguirán copiando las referencias en memoria de estos. Les recomiendo el curso POO intermedio donde profundiza este tema.

Spread Operator

Utilizando el spread operator, cogemos los valores de person y los insertamos directamente en X. Así evitamos anidar un abjeto dentro de otro
Con el spread operator, podemos sumar arrays, hacer copias, añadir nuevos elementos…

Fuente: https://dev.to/lydiahallie/interactive-javascript-quiz-2-4pi1

Los navegadores web usan dos tipos de memorias: Stack y Heap.

Stack

Es veloz, pero sin tanto espacio.

Aquí se guardan los valores primitivos (booleanos, strings, números…).

Heap

Es más lenta, pero permite guardar enormes cantidades de información.

De mis métodos favoritos ❤️ el array map, realmente te ayuda a hacer un código mucho más limpio y a implementar o mapear todo para evitar errores al momento de trabajar con arrays de objetos que no traigan la información en un formato correspondiente, por ejemplo, si el objeto trae los números en cadenas de caracteres puedes transformarlos en números dentro del map y evitarte validaciones futuras.

Podriamos agregar la propiedad tax de una manera un poco mas real de la siguiente manera:

const products = [
  { name: "Chiken", price: 43 },
  { name: "Ken", price: 12 },
  { name: "Horse", price: 234 },
];

const wTax = products.map((product) => {
  let thetax = product.price * 0.16;
  return {
    ...product,
    tax: thetax,
    total: thetax + product.price
  };
});

console.log("original", products);
console.log("with tax", wTax);

Tener en cuenta todos los parametros que puede usar la funcion map que pueden ser utiles para algun caso:
1. currentItem
2. currentIndex
3. originalArray

const objA = [{quantity:20, price:1}, {quantity:2, price:4}];
const objE = objA.map( (currentItem, currentIndex, originalArray) => {
  return { …currentItem,
    index: currentIndex,
    total: currentItem.quantity * currentItem.price
  };
});

Otra forma de evitar copiar las referencias en memoria es asi…

const orders = [
  {
    customerName: "Nicolas",
    total: 60,
    delivered: true,
  },
  {
    customerName: "Zulema",
    total: 120,
    delivered: false,
  },
  {
    customerName: "Santiago",
    total: 180,
    delivered: true,
  },
  {
    customerName: "Valentina",
    total: 240,
    delivered: true,
  },
];

/* Aqui viene lo interesante */

let withTax = JSON.parse(JSON.stringify(orders))
withTax.map(e=>e.tax=.19)
console.warn(orders)
console.log(withTax)
  • Donde JSON.stringify() Convertira un Objeto
    en un string

  • yyyy JSON.parse() Toma un string y
    devuelve un objeto sin importar que tan complejo sea

Os dejo 2 clases al respecto

Utilizando

  return {
    ...item,
    tax: 0.19,
  };

Podemos crear una copia del objeto original y modificar esa copia, agregando ese nuevo elemento, sin modificar al array original de objetos.

map nos sirve para recorrer los elementos de un array y transformarlos.

Syntaxis


const numeros = [1,4,5,15]; 
const dobles = numeros.map(function(numero,position,numeros){
    return numero * 2;
}
  1. se invoca el método map sobre el array original.
  2. map recibe como primer parametro la función transformadora. La que se va a ir invocando por cada elemento del array
  3. esta función recibe como parámetro el elemento del array que va a transformar.
  4. segundo parámetro la posición del elemento en el array
  5. El tercer parametro es el array original donde se invocó la función

Que joyita de clase 😮😮

Muy importante el manejo de los objetos ya que se toma la referencia en memoria y si se muta el resultado.

Para hecer una copia del objeto y hacer la copia debemos generar un nuevo objeto usando el operador (…) de ECMAScript 6

Genial, dónde le doy like a está clase?

Incluso podríamos hacer validaciones para agregar propiedades al nuevo arreglo que no afectarían al original

   const show=document.querySelector(".showArray");

        const arreglo=[
            {Name:'peter',
             age:23,
             adress:'Av 23 Fort laudardale'},
             {Name:'jhon',
             age:18,
             adress:'32 Road'},
             {Name:'Mary',
             age:20,
             adress:'5 av, Fl'}
        ]
           arreglo.map(person=>{
               let futureAge=parseInt(person.age)+10;
            show.innerHTML+=`
            <div>
             <li>${'mi nombre es '+person.Name}</li>
             <li>${'y tengo '+person.age+' años de edad'}</li>
             <li>${'y en 10 años tendré '+futureAge+' años de edad'}</li>

             
           </div>    
           `
           })
           const arreglo2=arreglo.map((person)=>{
            if(person.adress.includes('Fl')){
                country="EE.UU"
            }else{
                country="Other"
            }
               return{
                   ...person,
                   
                   country
               }
           })
          
           console.log(arreglo)
           console.log(arreglo2)
    </script>

A ver si lo entendí correctamente, al utilizar el método map para generar un nuevo array copiamos la referencia en memoria, esto quiere decir que al tener un nuevo array y modificarlo estamos editando tanto el original como la copia porque nuestro nuevo array no copia los valores del objeto como tal, sino la referencia en memoria (que incluye todo el objeto) y por esa razón se modifican los dos arrays, mientras que con el spread operator lo que hacemos es copiarnos los valores directamente del objeto, por ende el array original no se verá afectado ya que el nuevo tiene copia de sus valores y se harán las modificaciones solo en ese.
Nose si estará bien mi forma de entender, o si alguien tiene una forma mas fácil de explicarla

Hola [email protected]!
Me auto-reté a hacer esto en React xq lo tengo como objetivo de perfil profesional.

Comparto mi código:

import "./App.css";

function App() {
  const orders = [
    {
      customerName: "Nicolas",
      total: 60,
      delivered: true,
    },
    {
      customerName: "Zulema",
      total: 120,
      delivered: false,
    },
    {
      customerName: "Santiago",
      total: 180,
      delivered: true,
    },
    {
      customerName: "Valentina",
      total: 240,
      delivered: true,
    },
  ];

  const taxApply = (num) => {
    let tax = num * 0.19;
    return tax;
  };

  return (
    <div className="App">
      <header className="App-header">
        <h1>hola</h1>
        <ul>
          {orders &&
            orders.map((order) => (
              <li>
                <h4>{order.customerName}</h4>
                <h4>{order.total}</h4>
                <h4>{taxApply(order.total)}</h4>
              </li>
            ))}
        </ul>
      </header>
    </div>
  );
}

export default App;

asi renderiza:

cuando trabajamos con objetos hay que entender un concepto muy importante a la hora de copiarlos
La referencia en memoria:
Cuando creamos un objeto, este es almacenado en dos tipos de memorias:
memoria stack:
-Esta es una memoria dinámica pero con poco espacio

  • En esta memoria es donde se almacenan las inicializaciones de las variables, objetos, array, Junto con las declaraciones de los valores primitivos.

memoria heap:
-Esta es una memoria mas lenta pero mas ordenada y con mas espacio
-En esta memoria es donde se almacenan los arrays y los objetos

  • Cuando se inicializa y se declara un array o un objeto, los que se hace es almacenar el array/objeto en la memoria heap,
    y la declaración de la misma se almacena en la memoria stack
    Por lo tanto la declaración es un pointer desde la memoria stack hacia el objeto que esta en la memoria heap

No tenia ni idea sobre la referencia en memoria…

Os dejo 2 videos excelentes sobre el concepto de programacion funcional y el uso de estas funciones 😃

https://www.youtube.com/watch?v=3eLx9syx8iI&t=949s

El concepto al que hace referencia el prfe sobre pulir los datos se le llama data mining y es todo un arte -> acá os dejo una clase al respecto

https://platzi.com/clases/1566-bd/19832-data-mining/

Excelente, no tenía ni idea que esto pasara.

Quiero compartirles esto, si usas el comando

console.table(array);

Tendras una visualización mejor de tus array.

Con console.log:

Con console.table

Me imagino que la mutabilidad en los objetos sucede porque map solo trabaja en la memoria stack. Y como ahí solo guarda las referencias, no los valores, se afectan los valores en la heap.

Corríjanme si me equivoco.

Hice el archivo HTML

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>forEach</title>
  <style>
    body{
      width: 100%;
      background-color: blanchedalmond;
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
    }
  </style>
</head>
<body>
    <div id="app"></div>
    <div id="app2"></div>

    <script>
      const app = document.getElementById('app');
      const app2 = document.getElementById('app2');
      const orders = [
        {
          customerName: "Nicolas",
          total: 60,
          delivered: true,
        },
        {
          customerName: "Zulema",
          total: 120,
          delivered: false,
        },
        {
          customerName: "Santiago",
          total: 180,
          delivered: true,
        },
        {
          customerName: "Valentina",
          total: 240,
          delivered: true,
        },
      ];

      //Este nos trae solo los valores que queremos en esta ocasion "total"
      const rta = orders.map(items => {
        return `<h1>${items.customerName} - ${items.total} - ${items.delivered}</h1>`
      })

      app.innerHTML = rta.join('')

      //Este solo modifica el nuevo array y el original lo deja como esta
      const rta2 = orders.map(items => {
        const obj = {
          ...items,
          tax: 0.19
        }
        return `<h1>${obj.customerName} - ${obj.total} - ${obj.delivered} - ${obj.tax}</h1>`
      });
      app2.innerHTML = rta2.join('')
    </script>
</body>
</html>

Muy útil esta clase 💪

un dato interesante si necesitamos pasarle un atributo en especifico del objecto ejemplo total seria asi: ({propertyObject})
({total})

console.log('orginal', orders);
const resp = orders.map(({total}) => total);  
console.log('new', resp); //RESPUESTA SERIA new [ 60, 120, 180, 240 ]

Los primitivos se pasan por valor y los objetos se pasan por referencia, por ejemplo:

// Primitivos
let num = 10;
let num2 = num;
num2 = 2;
console.log( num );
console.log( num2 ); 

// Objetos
let car = { name: 'Mazda' };
let car2 = car;
let car2.name = 'BMW'
console.log( car );
console.log( car2 ); 

Para evitar el paso por referencia, tenemos métodos como Object.assign y el Spread Operator,

Ejemplo de la clase:

const rta2 = orders.map(order => ({...order, tax: 0.19}) );
const rta3 = orders.map(({...order}) => {
  order.tax = 0.19;
  return order;
});