No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

No se trata de lo que quieres comprar, sino de quién quieres ser. Invierte en tu educación con el precio especial

Antes: $249

Currency
$209

Paga en 4 cuotas sin intereses

Paga en 4 cuotas sin intereses
Suscríbete

Termina en:

12 Días
11 Hrs
51 Min
3 Seg

Deep copy con recursividad

9/20
Recursos

Con el Deep Copy podemos generar copias de objetos sin importar que estos posean objetos anidados o métodos dentro.

Aplicando Deep Copy en JavaScript

Veamos el siguiente ejemplo:

<// OBJETO ORIGINAL
const studentBase = {
  name: undefined,
  email: undefined,
  age: undefined,
  approvedCourses: undefined,
  learningPaths: undefined,
  socialMedia: {
    twitter: undefined,
    instagram: undefined,
    facebook: undefined,
  },
	hello() {
		 console.log("Hello, World!");
	}
};

// FUNCIÓN RECURSIVA
function isObject(subject) { // Comprueba si es un objeto
  return typeof subject == "object"; // Devuelve true o false
}

function isArray(subject) { // Comprueba si es una Array
  return Array.isArray(subject); // Devuelve true o false
}

// FUNCIÓN RECURSIVA
// Recibe un parametro que puede ser un objeto, array u otro tipo de dato
function deepCopy(subject) {
  let copySubject; // Esta variable se convertira en array, objeto u otro tipo de dato

  const subjectIsObject = isObject(subject); // ¿El parámetro es objeto?
  const subjectIsArray = isArray(subject); // ¿El parámetro es array?

  if (subjectIsArray) { // Si es array...
    copySubject = []; // Asignamos un array vacío donde iremos copiando 1 a 1 los datos
  } else if (subjectIsObject) { // Si es un objeto...
    copySubject = {}; // Asignamosun objeto vacío donde iremos copiando 1 a 1 los atributos
  } else { // Sino es array u objeto...
    // Entonces es un tipo de dato que se puede copiar sin problemas, retornamos dicho
		// dicho dato y terminamos con la ejecución de la fucnción.
		return subject;
  }
	
	// Continuamos con la ejecución de la función si el parámetro fue array u objeto: 
  for (key in subject) { // Recorremos cada uno de los atributos o datos del objeto o array
		// Comprueba si hay un objeto dentro del índice o atributo:
    const keyIsObject = isObject(subject[key]);

    if (keyIsObject) { // Si es verdad que hay un objeto dentro...
	      // Invocamos recursivamente la misma función:
				copySubject[key] = deepCopy(subject[key]); // 👀🔄
    } else { // Sino...
      if (subjectIsArray) { // Si el parámetro recibido por la función deepCopy es Array...
	        // Agregamos el elemento a la variable a retornar al final de la función:
					copySubject.push(subject[key]);
      } else { 
				// sino, significa que es objeto el parámetro y además no hay objetos anidados
				// en el elemento actual dentro del recorrido del bucle for, por tanto, asignamos
				// dicho elemento como valor a la propiedad correspondiente:
        copySubject[key] = subject[key];
      }
    }
  }

  return copySubject; // Finalmente retornamos el objeto/array copia
}>

Generemos un objeto copia utilizando la función recursiva e intentemos realizar modificaciones en el objeto copia y original:

<// OBJETO COPIA
const juan = deepCopy(studentBase);

// MODIFICACIONES EN EL OBJETO ORIGINAL
studentBase.socialMedia.twitter = "@student_twitter"

// MODIFICACIONES EN EL OBJETO COPIA
juan.socialMedia.instagram = "@juanDC"

// VEAMOS EN CONSOLA LAS DIFERENCIAS DEL OBJETO ORIGINAL Y LA COPIA
console.log(studentBase);
console.log(juan);

// Mensaje en consola
{
  name: undefined,
  email: undefined,
  age: undefined,
  approvedCourses: undefined,
  learningPaths: undefined,
  socialMedia: {
    twitter: '@student_twitter', 👈👈 👀
    instagram: undefined,
    facebook: undefined
  },
  hello: [Function: hello] 👈👈 FUNCIÓN
}
{
  name: undefined,
  email: undefined,
  age: undefined,
  approvedCourses: undefined,
  learningPaths: undefined,
  socialMedia: { 
		twitter: undefined, 
		instagram: '@juanDC', 👈👈 👀
		facebook: undefined 
	},
  hello: [Function: hello] 👈👈 FUNCIÓN
}
>

Podemos notar que los cambios en un objeto no afecta en los valores de las propiedades del otro. Logramos crear una copia de un objeto que no esté condicionada a que si el objeto original tiene objetos anidados o si tiene métodos dentro.

Conozcamos ahora cómo emplear la abstracción en JavaScript con simplemente objetos, es decir, sin utilizar clases. 🤔🚀

Contribución creada por: Martín Álvarez (Platzi Contributor)

Aportes 98

Preguntas 21

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

para mi esta es una de las clases que no entiendes por completo pero que con el tiempo estoy seguro lograr comprender. En conclusión me llevo que copiar objetos en Javascript es un poco laborioso.

Hola! Les comparto mi aporte de como entendi el codigo paso por paso:

Funcion bucle compleja pero en recursividad.

let array = [1,23,41,52,42,5,656,6,98]
let numeroArray = 0;

let fun = (numerito) => {
    if( numerito < array.length ) {
    let valorArray = array[numerito];
    console.log(valorArray);
    return fun(numerito + 1)
    } else {
        console.log("fin");
    }  
}

let y = fun(numeroArray);

Deep copy.

Utilizaresmos recursividad para crear copia de los objetos y que no se rompan si tenemos objetso dentro de objetos dentro de objetos, o si tenemos metodos dentro de nuestros objetos.

Bien, deep copy en muchos aspectos es un gran algoritmo con manejo de datos, recursividad, etc etc, por lo tanto ire escribiendo fracciones de codigo y explicandolas, y cua do termine de explicar todo, pondre el algoritmo completo.

const obj1 = {
    a: "a",
    b: "b",
    c: {
       d: "d",
       e: "e", 
    },
    editA() {
        this.a = "AAAAA";
    }
}; 
//lo de aca arriba es el objeto a copiar

function isObject(subject) {
    return typeof subject == "object"
}
function esUnArray(subject) {
    return Array.isArray(subject);
}
//estas 2 funciones son funciones de validacion de datos, estan seran llamads y se les pasaran un parametro, la mayoria de datos se puede validar con typeof, ergo, los arrays son los unicos que tienen un metodo espacial = Array.isArray(objetoAsaberSiEsUnArray)

function deepCopy(subject) {
    let copySubject;
//dentro de sta funcion sucedera todo,el copysubject guardara los datos, este esta esperando a saber si los datos son objetos,arrays u otras cosas como strings
    const subjectIsArray = esUnArray(subject);
    const subjectIsObject = isObject(subject);

//con las constantes subjectIsArray,   subjectIsObject trabajere los datos,  estas son las encargadas de llamar a  las funciones que hicimos fuera de la funcion deepCopy.
  

  if(subjectIsArray) {
        copySubject = [];
    } else if(subjectIsObject) {
        copySubject = {};
    } else {
        return subject;
    }

//por ultimo empezamos a trabajar con los datos ya validados, segun el dato que sea correspondiente, trbajaremos objeto,arrays u otros valores.
//2da parte del algoritmo
for(key in subject) {
//Creamos un bucle for, este bucle (a in b)se puede ejecutar en una estructura de datos como arrays, objetos. Este loop signfica que el elemento a pasara por TODA la estructura de datos de b, y claro, dependieno la posicion de a,este tendra el valor de donde este parado encima. ejemplo: 
//let array = [52,42,56];
//for(a in array) {
	//console.log(array[a]);
//}
        const keyIsObject = isObject(subject[key]);
//con keyIsObject VUELVO a validar si los datos DENTRO de la estructura de datos YA VALIDADA son objetos o datos. 

        if(keyIsObject) {
            copySubject[key] = deepCopy(subject[key]);
// si resulta que son objetos, entonces iremos copiando y pegando los datos en copySubject, y estos datos se iran copiando de manera identica y exitosa gracias la recursividad deepCopy(subject[key]);

} else {
            if(subjectIsArray) {
                copySubject.push(subject[key]);
            } else {
                copySubject[key] = subject[key]
            }
        }
    }
 //estos 2 ultimos casos son mas sencillos ya que simplemente se basa en arrays u elementos que no sean ni arrays ni objetos   
 
    return copySubject;
// Y al final de todo, la funcion debe devolver algo,verdad? en este caso, quien es el que almaceno todos los datos de el objeto que copiamos? el copySubject, bien, ese es quien retornamos.
} 

Hola compañeros 😀, estuve jugando un poco con el código de la case para entenderlo mejor, y se puede simplificar de esta forma, mas sencillo de leer:

function deepCopy(subject) {
  let copy;

  if (Array.isArray(subject)) {
    copy = [];
  } else if (typeof subject === "object") {
    copy = {};
  } else {
    return subject;
  }

  for (key in subject) {
    copy[key] = deepCopy(subject[key]);
  }

  return copy;
}

Ahora ustedes se preguntaran:
¿Porque en el ciclo for ya no hay validaciones?, esto es debido a que el valor key dentro del for va a corresponder a dos posibles valores: indices de un array, o keys de objetos, dependiendo que sea subject (un objeto o un array) , y como esta misma sintaxis sirve para objetos y arrays podemos usar la misma linea de código, teniendo encuenta que ya antes creamos copy con los valores {} o [] dependiendo si subject era un objeto o array

Jugando un poco con el debugger he visto como la variable let copySubject; empieza a obtener sus elementos
Imagen1
la function deepCopy identifica que es un objecto { } .

Imagen2
los dos primeros elementos ingresan normal: copySubject[key] = subject[key]; //{a,b}.

Imagen3
en el elemento c:{} identifica que hay un objeto .

Imagen4
ingresan de forma normal los elementos copySubject[key] = subject[key]; //{d,e}.

Imagen5
es el momento de ingresar la function editA(){} lo detecta como objeto.

Imagen6
con este ultimo paso, copia todo el contenido de la funcion y para a finalizar la function.

Deep Copy con recursividad

Se dice que el objeto tiene un Deep Copy cuando cada propiedad del objeto apunta a una copia separada, incluso si la propiedad apunta a un objeto (valores de referencia). Se crea una copia separada del objeto de referencia para el objeto de destino. En caso de copia profunda, las propiedades de referencia del objeto de origen y las propiedades de referencia del objeto de destino apuntan a diferentes ubicaciones de memoria.

Resumen de Deep Copy

  • El objeto de destino contiene una copia separada del nombre, la edad y la designación.
  • Instancias separadas de tipos de valor. Se crea una referencia separada para objetos complejos (“dirección”)

La propiedad “Dirección” de los objetos de origen y destino apuntan a diferentes ubicaciones de memoria. Si el usuario actualiza la propiedad de la dirección en el objeto de origen, las actualizaciones no se reflejan en el objeto de destino.

var userName = {
  name: "Mayank Gupta",
  age: 30,
  designation: "Developer",
  address: {
    street: "Rohini",
    city: "Delhi"
  }
}

Lectura importante!

Deep and Shallow Copy in JavaScript

Código Clase

const obj1 = {
    a: 'a',
    b: 'b',
    c: {
        d: 'd',
        e: 'e',
    },
    editA() {
        this.a = 'Abcd'
    }
};

function isObject(subject) {
    return typeof subject == "object";
}
function isArray(subject) {
    return Array.isArray(subject);
}

function deepCopy(subject) {
    let copySubject;

    const subjectIsObject = isObject(subject)
    const subjectIsArray = isArray(subject)
 
    // inicializamos la variable copySubject segun su tipo de dato
    if (subjectIsArray) {
        copySubject = [];
    } else if (subjectIsObject) {
        copySubject = {};
    } else {
        return subject;
    }

    // Empieza la recursividad
    for (key in subject) {
        const keyIsObject = isObject(subject[key]); // propiedad de nuestro elemento

        if (keyIsObject) {
            copySubject[key] = deepCopy(subject[key]) // Si la propiedad es un objeto, se vuelve a llamar a deepCopy para volver a hacer las asignaciones por cada una de las propiedades de los objetos.
        } else {
            if (subjectIsArray) {
                copySubject.push(subject[key])
            } else {
                copySubject[key] = subject[key]
            }
        }
    }

    return copySubject;
}

// Pruebas en devTools
// const obj2 = deepCopy(obj1);

// obj1
// obj2

// obj1.a = 'AMORMIO'

// obj2.a = 'Si estoy debajo del vaivén de tus piernas'

// obj1
// obj2

Tomando como inspiración los aportes de @irvingjuarez y @lgfh, les comparto una solución efectiva y más corta:

.

.

P.D. Dejé los statements a la derecha de los if para que no ocupara más líneas y la imagen no fuese más larga.

Esta clase me hizo volar la cabeza pero todo totalmente comprensible! El mejor profe!

Me parece que hay un momento en el que la clase se hace confusa y es el momento en que el profe decide en el ciclo For In anidar el if de si subjectIsArray, y ademas de la anidación, que utilice subjectIsArray como validación sin pasarle ningun parametro, a mi parecer debió generar un keyIsArray al igual que lo hizo con keyIsObject, y de paso no anidar el if, a que no tiene proposito en si mismo.
les dejo el mismo codigo solo que con unas pequeñas modificaciones a ver que les parece.

const obj1 = {
  a:"b",
  c:"d",
  f:"g",
  capC(prop) {
    this.prop = toUpperCase(this.prop)
  },
  h:"i",
  j:"k",
}

function isObj (elm) {
  return Object.prototype.toString.call(elm) == '[object Object]'
  // return typeof elm == 'object'
}

function isArr (elm) {
  return Array.isArray(elm)
}

function deepCopy (elmToCopy) {
  let copyElm
  
  let itsAnObject = isObj(elmToCopy)
  let itsAnArray = isArr(elmToCopy)
  
  if(itsAnArray)
  {
    copyElm = []
  } 
  else if (itsAnObject)
  {
    copyElm = {}
  } 
  else 
  {
    return elmToCopy
  }
  
  for(subElm in elmToCopy)
  {
    const subElmItsObj = isObj(elmToCopy[subElm])
    const subElmItsArr = isArr (elmToCopy[subElm])
    
    if(subElmItsObj)
    {
      copyElm[subElm] = deepCopy(elmToCopy[subElm])
    } 
    else if (subElmItsArr)
    {
      copyElm.push(elmToCopy[subElm])
    } else {
      copyElm[subElm] = elmToCopy[subElm]
    }
  }
  
  return copyElm
}

let obj2 = deepCopy(obj1)

console.log(obj2)


Tuve que ver el video 3 veces para lograr comprenderlo, pero al fin pude lograrlo, creo que las clases de Juan son de lo mejor y su energía lo es todo 😄

Una versión acortada y simplificada que estuve probando 😛 :

const deepCopy = elem => {
  if(!isObject(elem)) return elem
  
  const copyOfElem = isArray(elem) ? [] : {}
  
  for(key in elem){
    const current = elem[key]
    
    copyOfElem[key] = isObject(current)
    		? deepCopy(current)
    		: current
  }
  
  return copyOfElem
}

El funcionamiento es el mismo, pero utiliza algunos trucos para acortar espacio

  1. Solo verifica si es un objeto porque los arrays también son objetos, así que solo puede ser o un objeto o un primitivo
  2. Para inicializar la copia como solo tiene 2 opciones (array u objeto) entonces usa una ternaria
  3. Con el for in ya recorre el array así que solo debe verificar si el elemento es un objeto o agregar el elemento en esa posición

Hice algunas pruebas y funcionan igual, pero a lo mejor se me escapa algún edge case, si lo ven me serviría mucho, grax ;D

Aqui hay un error, ya que en la funcion isObject, incluso aunque le pases como argumento un array, te da true. Sin embargo, existe otra forma de validar eso:
.
El función debería quedar así;

function isObject(subject){
  return Object.prototype.toString.call(subject) == "[object Object]";
}

Sabemos si es un array si el string es [object Array]

Gracias a las nuevas features de JavaScript😎, hoy tenemos una nueva función que nos puede ayudar para aquellos casos en los que se quiera clonar un objecto o arreglo y no nos baste con un shallow copy 🤔.

La función se llama structuredClone, está permite hacer un deep copy basado en un algoritmo del mismo nombre (Structured Clone) de tal forma que sea mucho mas facil para los devs hacer deep copy de sus estructuras de datos 😮.

Aquí un ejemplo de uso:

const myDeepCopy = structuredClone(myOriginal);

Sin embargo esto es relativamente nuevo al dia de hoy y tiene ciertas limitaciones (como el caso donde se tengan funciones dentro del objeto), si quieren leer más al respecto les dejo un articulo donde lo explican más a detalle 😀.

esta clase si que me mareo tuve que verla varias veces!! es un excelente profe pero este tema me pudo xD a volver a mirar hasta comprender

Holaa, comparto mi solucion a la funcion deepCopy

function typeOfElem(elem) {
  let result;

  switch (Object.prototype.toString.call(elem)) {
    case "[object Object]":
      result = "object";
      break;
    case "[object Array]":
      result = "array";
      break;
    default:
      result = "no problem";
      break;
  }

  return result;
}

function deepCopy(elem) {
  let copy;
  let elemType = typeOfElem(elem);

  if (elemType === "array") {
    copy = [];
  } else if (elemType === "object") {
    copy = {};
  } else {
    return elem;
  }

  for (let item in elem) {
    let elemType2 = typeOfElem(item);

    if (elemType2 === "object") {
      item = deepCopy(item);
    }

    if (elemType === "array") {
      copy.push(item);
    } else {
      copy[item] = elem[item];
    }
  }

  return copy;
}

hoy siento que no podría hacer esto solo ni de broma, pero espero volver a ver este comentario en un tiempo más y reirme de mí mismo.

Acá esta mi aporte, utilice algunas especificaciones de ES6+
Pueden ver el resto de los retos que he resuelto en este y otros cursos de esta misma escuela acá: https://github.com/EdinsonRequena/JsSchool
Espero les sirva de ayuda ❤️

const isObject = subject => typeof subject == 'object'
const isArrayFunc = subject => Array.isArray(subject)

const deepCopy = subject => {
    let copySubject

    const subjectIsObject = isObject(subject)
    const subjectIsArray = isArrayFunc(subject)

    if (subjectIsArray) copySubject = []
    else if (subjectIsObject) copySubject = {}
    else subject

    for (let key in subject) {
        const keyIsObject = isObject(subject[key])
        if (keyIsObject) copySubject[key] = deepCopy(subject[key])
        else subjectIsArray ? copySubject.push(subject[key]) : copySubject[key] = subject[key]
    }

    return copySubject
}

const obj = {
    name: 'Andrea',
    lastName: 'Vinas',
    email: 'andre',
    age: 21,
    objectTest: {
        a: 'a',
        b: 'b',
        1: '1',
    },
    aprovedCourse: ['JavaScript', 'NodeJS', 'ReactJS'],
    addCourse(newCourse) {
        this.aprovedCourse.push(newCourse);
    }
}

const example = deepCopy(obj)

Maneras de copiar un Array(Deep and shallow)

Existen diferentes maneras de copiar un array, una de ellas es con el método slice(), que nos permite copiar un array sin modificar el original.

var original = [true, true, undefined, false, null];

//slice()
var copy1 = original.slice(0);

//spread operator
var copy2 = [...original];

Estas tienden a no funcionar cuando hay un objeto o un arreglo dentro de un array. Cuando pasa eso necesitas un deep copy
shallow copy:

var deepArray = [["Carlos"]];
var shallowCopy = deepArray.slice(0);

shallowCopy[0].push("es chevere");
console.log(deepArray[0], shallowCopy[0]);
// ["Carlos", "es chevere"]


var deepCopy = JSON.parse(JSON.stringify(deepArray));
deepCopy[0].push("es chevere");
console.log(deepArray[0],deepCopy[0])


Cuando hacemos copy, copiamos el pointer del original array

a pesar que tuve que repetir la clase un par de veces, y detenerme en la explicacion y reflexionar lo que decia el profe, es gratificante poder entender el codigo, y asi mejorar nuestra comunicacion con nuestra maquina, muy satisfecho con esta clase.

Tuve que releer el código del bucle un par de veces, pero finalmente logré entenderlo 😄

La mejor forma para entender esta clase es usando debugger en el navegador es lo máximo

Está muy buena la clase y más que todo para hacer el ejercicio 👏, pero hoy en día ya tenemos una forma nativa de como hacer copias profundas en JS.

Por si no lo conocían se llama structureClone aquí les paso la doc por si la necesitan. https://developer.mozilla.org/en-US/docs/Web/API/structuredClone

Pero ojo con el soporte para navegadores antiguos
https://caniuse.com/?search=structuredClone

Nunca me imagine que copiar un Objeto fuese de esta manera tan compleja

Me perdí entre tantos objetos 😦

Así fu como lo entendí

//DEEP COPY


    //Funciones para comprobar que el tipo de dato

function isObject(subject){
    return typeof subject == "object"; // recordar que los arrays tambien son de tipo objeto en js
}

function isArray(subject) {
    return Array.isArray(subject);
}

    // Empieza la funcion de copiado profundo

Empieza la funcion de copiado profundo

function deepCopy(subject) {
    let copySubject; // Inicializa la constante que enviara al final

comprueba que la variable enviada sea un array o un objeto

    const subjectIsObject = isObject(subject); // si es array u objeto va a dar true

    const subjectIsArray = isArray(subject); // sólo si es array dara un true

Es necesario que este ciclo if compruebe primero que es un array, ya que como se vio anteriormente los array también son objetos

    if (subjectIsArray) {
        copySubject = []; // transforma la variable inicializada en un array
        console.log("Es array");
    } else if (subjectIsObject) {
        copySubject = {}; // transforma la variable inicializada en un objeto
        console.log("Es objeto");
    } else {
        return subject;
 // en caso de que no sea una variable tipo objeto termina la funcion enviando solo el dato a copia
    }

    for (key in subject) {
        const keyIsObject = isObject(subject[key]); // Comprueba que la Key sea un variable de tipo objeto
        if (keyIsObject) {
            copySubject[key] = deepCopy(subject[key]); // En caso que lo sea llamara la funcion deepCopy de nuevo
        } else {
            if (subjectIsArray) {
                copySubject.push(subject[key]); // Se envia el valor de la Key que no es de tipo objeto (Number, String o boolean) al array copiado
            } else {
                copySubject[key] = subject[key]; // Se evia copia de la key al objeto copiado
            }
        }
    }
    return copySubject;};

`

Les comparto como anoté lo que hace la función deepCopy para mis apuntes:

  1. Recibe como parámetro una variable.
  2. Se verifica si es un objeto, array o otro tipo de variable.
    1. Si es objeto o array entra en un ciclo. Sino retorna la copia de la variable.
  3. Si se entra al ciclo, por cada elemento o atributo del objeto o array
    1. Se verifica nuevamente si es objeto, array o variable.
      1. Si este atributo es un objeto, se llama de nuevo a la misma función. (Acá esta la recursividad). Y se vuelve al primer paso hasta copiar este objeto.
    2. Si es un array se utiliza el método push.
    3. Si es otro tipo de variable solo se hace una asignación normal.
  4. Finalmente el ciclo acaba y se devuelve el array o el objeto copiado.

Deep copy con recursividad

const obj1 = {
  a: 'a',
  b: 'b',
  c: {
    d: 'd',
    e: 'e',
  },
  editA() {
    this.a = 'AAAAA';
  }
};

function isObject(subject) {
  return typeof subject === 'object' && subject !== null;
}

function isArray(subject) {
  return Array.isArray(subject);
}

function deepCopy(subject) {
  let copySubject;

  const subjectIsArray = isArray(subject);
  const subjectIsObject = isObject(subject);

  if (subjectIsArray) {
    copySubject = [];
  } else if (subjectIsObject) {
    copySubject = {};
  } else {
    return subject;
  }

  for(key in subject) {
    const keyIsObject = isObject(subject[key]);

    //*if else - if else
    keyIsObject ? copySubject[key] = deepCopy(subject[key]) : subjectIsArray ? copySubject.push(subject[key]) : copySubject[key] = subject[key];
  }

  return copySubject;
}

deepCopy(obj1);

Excelente clase, cada detalle bien llevado hasta aqui.

No entendí :c

Algo curioso que note jugando con la funcion ‘isObject’ es que devuelve ‘true’ con los arrays tambien, incluso haciendo mas estricta la comparacion con ===

function isObject(subject) {
  return typeof(subject) == 'object';
}
const object = {};
const array = [];

console.log(isObject(array))  // true

Recomiendo MUCHO ir al enlace de “Lecturas recomendadas” que dejo el profe (https://medium.com/technofunnel/deep-and-shallow-copy-in-javascript-110f395330c5)
Vale mucho la pena tomarse un tiempo y leerlo detenidamente, un gran aporte para el entendimiento del curso.

Me cuesta entender la recursividad ya que es un concepto realmente difícil de comprender por esta razón estuve realizando búsquedas para de como funciona y encontré este video que me ayudo a comprender un poco mas la recursividad, pero espero en mi futuro tener mas claro este concepto para saber cuando es una buena opción usarlo.

No hay caso. No puedo hacer que funcione. Al modificar un objeto se modifica también el otro, incluso copiando el codigo que está en recursos.

Creo que lo que hace confuso la clase es que es muy teorico, y no vemos un resultado hasta el final. Entre toda la explicacion y lineas nos perdemos, son 14 minutos seguidos de codigo sin ver resultado.

Esta clase es la clase para ver varias veces, leer todos los comentarios, leer las preguntas y respuestas y aun así tener la sensación que algo falta como un vacío que no se comprende.
Buena clase

juan ayuda!

No entendí ni 🐥. Me toca volver a ver la clase.

Me queda una duda en este punto.
Los arrays dentro de JavaScript también son Objetos, por lo tanto, la validación dentro de la función isObject, también va a retornar true cuando sele pase un array. En consecuencia, se podría ejecutar el if y el else if en el condicional. Debido a que no. La están mandando a salir del condicional cuando es un array.

me hizo recordar cuando en la universidad nos pidieron elaborar un programa que le pegaras un bloque de codigo y te dijera que lenguaje era cuantas variables se habian creado y si existian condicionales y cuantos eran… analizar linea por linea los texto, en este caso analizando cada loop del for in

// Esta función comprueba si un objeto es válido (no nulo) y es un objeto.
function isObject(obj) {
  return obj !== null && typeof obj === "object";
}

// Esta función comprueba si una variable es un array.
function isArray(arr) {
  return Array.isArray(arr);
}

// Esta es la función principal que se encarga de hacer una copia profunda de un objeto o array.
function deepCopy(subject) {
  // Primero, comprobamos si el sujeto es un objeto o array válido.
  if (isObject(subject)) {
    // Si es un array, creamos una copia vacía.
    // Si no, creamos un objeto vacío.
    const copySubject = isArray(subject) ? [] : {};

    // Usamos Object.entries() para obtener tanto la clave como el valor de cada propiedad.
    for (const [key, value] of Object.entries(subject)) {
      // Comprobamos si el valor de la propiedad es un objeto o un array.
      if (isObject(value)) {
        // Si es un objeto o un array, llamamos a deepCopy() de forma recursiva para copiarlo.
        // Luego asignamos la copia al objeto o array nuevo.
        copySubject[key] = deepCopy(value);
      } else {
        // Si no es un objeto o un array, simplemente copiamos el valor al objeto o array nuevo.
        copySubject[key] = value;
      }
    }

    // Devolvemos el objeto o array nuevo con todas las propiedades copiadas.
    return copySubject;
  } else {
    // Si no es un objeto o array válido, simplemente devolvemos el valor original.
    return subject;
  }
}

En resumen, la función deepCopy realiza una copia profunda de un objeto o array en JavaScript. Primero comprueba si el sujeto es un objeto o array válido. Si es válido, crea un nuevo objeto o array vacío y utiliza un bucle for…of para recorrer todas las propiedades del objeto o array original. Para cada propiedad, comprueba si su valor es un objeto o array. Si lo es, llama a deepCopy de forma recursiva para copiarlo y asigna la copia al objeto o array nuevo. Si no lo es, simplemente copia el valor al objeto o array nuevo. Finalmente, devuelve el objeto o array nuevo con todas las propiedades copiadas. Si el sujeto no es un objeto o array válido, simplemente devuelve el valor original.

Hola a todos, les comparto mi código de deep copy.

El código copia todo hasta la capa más profunda, vi que el código de la clase no llega tan profundo, así que le mejoré esa parte.

Les dejo un sreenshot del código y el código como tal.
Todo feedback es bienvenido. 😄

function isObjectOrArray (element) {
	const ELEMENT_IS = {
		'[object Object]' : 'object',
		'[object Array]'  : 'array'
	};
	const TYPE_ELEMENT = Object.prototype.toString.call(element);
	const IS_ELEMENT_ANY = TYPE_ELEMENT !== '[object Object]' && TYPE_ELEMENT !== '[object Array]';
	const RESULT = (IS_ELEMENT_ANY)
		? 'any'
		: ELEMENT_IS[TYPE_ELEMENT];

	return RESULT;
}

function deepCopy (subject) {
	const SUBJECT_IS = isObjectOrArray(subject);

	if (SUBJECT_IS === 'any')
		return subject;
	const COPY_SUBJECT = (SUBJECT_IS === 'array')
		? []
		: {};

	for (const KEY in subject) {
		const IS_KEY_ANY = isObjectOrArray(subject[KEY]) === 'any';

		COPY_SUBJECT[KEY] = (IS_KEY_ANY)
			? subject[KEY]
			: deepCopy(subject[KEY]);
	}

	return COPY_SUBJECT;
}

Esta clase si me exploto la cabeza JAJA.
Pero nada que no sea entendible, solamente es de repasarlo y practicar!

Una parte de mi se emociona por el desafio que representaria usar una funcion recursiva sin generar un “Stack Overflow”.
Además, pienso que al momento de implementar dicha funcionalidad el código sería más escalable. En cuanto a proyectos grandes.

Toda la clase o el tema estuvo muuuy loco y me volo la cabeza una parte en especial.
este fue mi objeto de prueba:

const obj1 = {
  a: "a",
  b: "b",
  c: {
    d: "d",
    e: "e"
  },
  f: ["♑️", "💀", "☯️", "💻"],
  g: () => {
    console.log("hi i'm a method in 'g'");
  },
  h: [1,2,3,{cuatro: '4', editA: () =>{this.a = 'AAAAA'}}]
};

Como pueden ver tiene arrays dentro de sus propiedades y a la vez arrays con objetos como elementos.
Mi problema principalmente era que no entendía cómo validamos que una de las propiedades fuera un array, si solamente estamos validando con isObject(subject[prop]) y no con isArray… Luego todo cobro sentido cuando recorde que un array (así como muchas cosas en JS) es un objeto:

Noten que las dos validaciones de isArray e isObject son true en mi subject que es un array dentro de mi objeto. Asi que un Array([ ]) es un Array(obviamente) y es un objeto(al menos en nuestra validación con typeof , pero un objeto ({ })es un objeto(obviamente) y no es un array.

Bueno al menos esto fue lo que deduje y entendí, si estoy equivocado en mi razonamiento diganme para no vivir engañado otra vez XD.

Una Deep Copy establece una copia de los elementos que forman parte del objeto, pero omitiendo la copia de sus referencias. Es decir, creando un nuevo objeto en memoria, copiando o clonando su original, lo que representa un snapshoot del objeto en sí mismo en un momento dado.

Hola!!, llegue un año tarde, pero este seria una propuesta para lo hecho, no se que tan bien esta, pero lo interesante es que funciona

const obj1 = {
    a: 'a',
    b: 'b',
    c: {
        d: 'd',
        e: 'e'
    },
    editA() {
        this.a = 'AAAA'
    }
}

const elements = {
    "[Object Object]": {},
    "[Object Array]": []
}

function typeOfElement(subject) {return Object.prototype.toString.call(subject)}

function deepCopy(subject){
    let copySubject;
    
    const subjectIsAnElement = typeOfElement(subject);
    
    copySubject = elements[subjectIsAnElement] || subject
    
    for(let key in subject){
        const keyIsElement = typeOfElement(subject[key]);
        
        if(keyIsElement.includes('Object')) copySubject[key] = deepCopy(subject[key])

        keyIsElement.includes('Array') 
        ? copySubject.push(subject[key]) 
        : copySubject[key] = subject[key]
    }
    return copySubject;
}

deep copy copiado de objetos sin errores

Cabe destacar algo aquí y es que chequear tipos con typeof no es la mejor manera de hacer las cosas en JS.
.
Recordemos que en Javascript todo es un objeto y a veces un typeof === 'object' puede no ser todo lo confiable que esperarías, por ejemplo:

typeof null === 'object' // true
typeof [] === 'object' // true

Hay muchos casos en donde este tipo de comprobaciones no son de fiar, es preferible muchas veces ingeniarselas un poquito y pensar más allá… por ejemplo ¿Que es lo que todo objeto literal tiene? Pues, keys. Entonces:

if (Object.keys(subjectIsObject).length) {
  ...
}

Lo anterior sería una solución básicamente infalible, si el item devuelve un array, entonces ya sabes que es un literal.

Este sería un buen ejercicio de leetcode 😃

Costo un poco pero al final salió, acá dejo una solución
que hice antes de ver la clase como reto!

function recursiveCopy (src,target){    
  
    for(props in src){
        let aux;
        if( isObject(src[props]) && !isArray(src[props])){
            aux = props;
            target[aux] = {};
            recursiveCopy(src[props], target[aux]);
        }else if(isArray(src[props])){
            aux = props;
            target[aux] = [];
            for(index of src[aux]){
                recursiveCopy(src[props],target[aux]);
            }
        }else{
            target[props] = src[props] 
        }       
    }
}

function isObject(prop){    
    return typeof prop === "object";
}

function isArray(prop){
    return Array.isArray(prop);
}
//esto es declarar la variable
let copySubject;

//Esto es inicializarla
copySubject = "cualquierValor";

Tenia la duda si dentro del obj1 hay un Array, y luego de hacer el const obj2 = deepCopy(obj1), trato de modificar el Array del obj1 agregando con push un valor, al probar en console, no se va a modificar el obj2 En Resumen: funciona tambien si dentro de mi objeto tengo Arrays

Aqui dejo mi versión refactorizada de deepCopy:

function deepCopy(subject) {
  if (typeof subject !== 'object') return subject;
  const copySubject = Array.isArray(subject) ? [] : {};
  Object.keys(subject).forEach(key => {
    copySubject[key] = deepCopy(subject[key]);
  })
  return copySubject;
}

Debugeado a mano para quienes no sepan que esta pasando a la perfeccion ❤️

function deepCopy(subject) {
    let copySubject;

    const subjectIsObject = isObject(subject);
    const subjectIsArray = isArray(subject);

    if (subjectIsArray) 
    {
        copySubject = [];
        console.log("Inicializammos en ", copySubject);
    } 
    
    else if (subjectIsObject) 
    {
        copySubject = {};
        console.log("Inicializamos en ", copySubject);
    } 
    else 
    {
        return subject;
    }

    for (key in subject) 
    {
        const keyIsObject = isObject(subject[key]);

        if (keyIsObject) 
        {
            copySubject[key] = deepCopy(subject[key]);
            console.log(copySubject, "BandObject");
        } 
        
        else 
        {
            if (subjectIsArray) 
            {
                copySubject.push(subject[key]);
                console.log(`push of ${subject[key]} : BandArray`);
            } 

            else 
            {
                copySubject[key] = subject[key];
                console.log(copySubject, " BandNormie");
            }
        }
    }

    return copySubject;
}

Si ven algun error agradezco de sus comentarios

Simplificándolo un poco, el código quedaría así:

function deepCopy(element) {
  let copy;
  
  if (Array.isArray(element)) copy = [];
  else if (typeof element === "object") copy = {};
  else return element;
  
  for (item in element) {
    copy[item] = deepCopy(element[item]); 
  }
  return copy;
}

En ese caso yo lo hago asi… estoy en el 2030

//objeto ejemplo
const original= {
    name: "Pedrito",
    lastName: "Roca",
    personalinformation: {
       date: "11-11-2222",
       phone: 1122334455, 
    },
    editA() {
        this.name = "Pietro";
    },
    unascosas:[1,2,3,{a:"holaa", b:"lalalsl", c:23},5,6]
}; 

//metodo ultrasuperfantastico para copiar
const copia = {...original};

console.log(original);
console.log(copia);

Mi propuesta del algoritmo

function miDeepCopy(subject){
    let copySubject;
    if (typeof subject === 'object' && subject !== null) {
        copySubject = {};
    } else if(Array.isArray(subject)){
        copySubject = [];
    }else{
        return subject;
    }

    for(let i in subject){
        if(typeof subject[i] === 'object' && subject[i] !== null){
            copySubject[i] = miDeepCopy(subject[i]);
        }else if(Array.isArray(subject[i])){ //if it is an array
            copySubject[i] = subject[i].slice();
        }else{
            copySubject[i] = subject[i];
        }
    }
    return copySubject;
}

me siento satisfecho de aprender a la primera esto, puedo mimir en paz hoy


//Original object
const obj1 = {
    a: "a",
    b: "b",
    c: {
        d: "d",
        e: "e",
    },
    // f: ["apple", "banana"],
    editA() {
        this.a = "aaaa";
    }
};

//----------- Recursion. Recursive function

//Validators
function isObject(subject) {
    return typeof subject == "object";
}

function isArray(subject) {
    return Array.isArray(subject);
}

//DeepCopy function
function deepCopy(subject) {
    let copySubject;

    //Validator inside the function
    const subjectIsObject = isObject(subject);
    const subjectIsArray = isArray(subject);

    //Initialize the variable copySubject 
    if(subjectIsObject) {
        copySubject = {};
    } else if (subjectIsArray) {
        copySubject = [];
    } else {
        return subject;
    }

    //For loop
    for (key in subject) {
        //Check if the key is an object
        const keyObject = isObject(subject[key]);
        const keyArray = isArray(subject[key]);
        //Make conditionals. Object, array, something else.
        if(keyObject) {
            copySubject[key] = deepCopy(subject[key]);
        } else {
            if(keyArray) {
                copySubject.push(subject[key]);
            } else {
                copySubject[key] = subject[key];
            }
        }
    }
    return copySubject;
}

Esta clase podría llegar a ser un poco confusa si no se tienen bien los fundamentos, básicamente estamos reduciendo los objetos a datos primitivos los cuales guardan el valor y no la referencia en memoria, por lo cual al copiarlos estamos copiando el valor que tienen guardado.

Yo simplemente hubiese usado el desestructurador de objetos y sha, jaja

Pero entiendo que la recursividad era par dar un ejemplo de su uso

const obj1 = {
  a: "a",
  b: "b",
  c: {
     d: "d",
     e: "e", 
  },
  editA() {
      this.a = "AAAAA";
  }
};
function isArray (subject) { return Array.isArray(subject) };
function isObject (subject) { return typeof subject == "object" };

function deepCopy(subject) {
  let copySubject;
  const subjectIsArray = isArray(subject);
  const subjectIsObject = isObject(subject);

  if(subjectIsArray) copySubject = [];
  else if(subjectIsObject) copySubject = {};
  else return subject;

  for( key in subject ) {
    const keyIsObject = isObject(subject[key]);
    if(keyIsObject) {
      copySubject[key] = deepCopy(subject[key]);
    } else {
      if(subjectIsArray) {
        copySubject.push(subject[key]);
      } else {
        copySubject[key] = subject[key];
      }
    }
  }

  return copySubject;
}  

Les dejo mis apuntes de la clase donde tambien revisar mis apuntes del curso en gitbook:
teniendo como base el siguiente objeto con metodos vamosa ir aplicando la recursividad con el deep Copy:

const obj1 = {    a: "a",    b: "b",    c: {        d: "d",        e: "e",    },    editA() {        this.a = "AAAAAA";    }};

Validaremos si nuestro objeto de prueba es un objeto o si es un array, en el uno utilizaremos la palabra reservada typeof que nos permite validar si nuesto objetodePrueba es un objeto o lo que le pidamos, y con el array llamamos al superprototypoArray y luego a su metodo estatico isArray.

function isObject(subject) {    return typeof subject == "object";}
function isArray(subject) {    return Array.isArray(subject);}

Para hacer el deepcopy vamos a validar si es un objeto o un array y de acuerdo a eso validaremos y daremos una respuesta de copiado según sea un objeto o un array

function deepCopy(subject) {    
	let copySubject;
        const subjectIsObject = isObject(subject);
	const subjectIsArray = isArray(subject);
        if (subjectIsArray) {
        copySubject = [];
	} else if (subjectIsObject) {        
	copySubject = {};
    	} else {
        return subject;
    }        for (key in subject) {
        const keyIsObject = isObject(subject[key]);
        if (keyIsObject) {
            copySubject[key] = deepCopy(subject[key])
        } else {
            if (keyIsObject) { 
                 copySubject[key] = deepCopy(subject[key]);
	} else {
                if (subjectIsArray) {
                    copySubject.push(subject[key]);
                } else {
                    copySubject[key] = subject[key];
                }
            }
        }
    }        return copySubject;
}

De esta forma iteramos la copia de nuestros objetos por cada uno de sus valores, ya tengan otros objetos u otros arrays dentro de ellos, incluyendo a sus métodos.

Excelente clase 😀

.

La Razon de La Recursion es Pasar la copia del objeto creando funciones recursivas que aplican en deepCopy para ir elemento / elemento copiando eel Valor de nuestros subObjetos && Arrays() para evitar las copias afecten al ObjetoOriginal .
Graciasss structuredClone
He añadido un par de console.log( ) y a mí me ha ayudado un poquito más (aunque el ejemplo estaba ya de por sí muy bien pensado, no creo que esto se pueda explicar mejor 🫡) ```js const obj14 = { a: 'a', b: 'b', c: { d: 'd', e: 'e' }, editA() { this.a = 'AAAAAAA' }, undoEditA() { this.a = 'a' } } function isObject(anything) { console.log('calling isObject(' + anything + ')') return typeof anything === "object" } function deepCopy(toCopy) { console.log('Calling deepCopy(' + toCopy + ')') let copied const toCopyIsObject = isObject(toCopy) const toCopyIsArray = Array.isArray(toCopy) if(toCopyIsObject) { copied = {} } else if(toCopyIsArray) { copied = [] } else { return toCopy } for(key in toCopy) { const keyIsObject = isObject(toCopy[key]) const keyIsArray = Array.isArray(toCopy[key]) if(keyIsObject) { copied[key] = deepCopy(toCopy[key]) console.log('calling deepCopy(' + toCopy[key] + ')') } else if(keyIsArray) { copied.push(toCopy[key]) } else { copied[key] = toCopy[key] } } return copied } const obj15 = deepCopy(obj14) ```
Lo hice un poco diferente, pero funciono bien, si hay algo que deje pasar, estoy abierto a los comentarios. ```js const person ={ name: 'Jhon', age: 32, address: { country: 'USA', city: 'LA' }, pets: ["perro", "gato"], saludar: function(){ console.log('Hola'); } } function isAnObjectOrAnArray(obj){ if(Array.isArray(obj)){ return "is Array"; } if(typeof(obj)==='object'){ return "is Object"; } } function deepCopy(obj){ let objCopy; if(isAnObjectOrAnArray(obj)== "is Array"){ objCopy = []; } else if(isAnObjectOrAnArray(obj)== "is Object"){ objCopy = {} }else{ return obj; } for(let key in obj){ if (obj.hasOwnProperty(key)){ if (isAnObjectOrAnArray(obj[key]) === "is Array" || isAnObjectOrAnArray(obj[key]) === "is Object"){ objCopy[key] = deepCopy(obj[key]); }else{ objCopy[key] = obj[key]; } } } return objCopy; } const copiaPersona = deepCopy(person); console.log(person); console.log(copiaPersona); ```const person ={ name: 'Jhon', age: 32, address: { country: 'USA', city: 'LA' }, pets: \["perro", "gato"], saludar: function(){ console.log('Hola'); }} function isAnObjectOrAnArray(obj){ if(Array.isArray(obj)){ return "is Array"; } if(typeof(obj)==='object'){ return "is Object"; }} function deepCopy(obj){ let objCopy; if(isAnObjectOrAnArray(obj)== "is Array"){ objCopy = \[]; } else if(isAnObjectOrAnArray(obj)== "is Object"){ objCopy = {} }else{ return obj; } for(let key in obj){ if (obj.hasOwnProperty(key)){ if (isAnObjectOrAnArray(obj\[key]) === "is Array" || isAnObjectOrAnArray(obj\[key]) === "is Object"){ objCopy\[key] = deepCopy(obj\[key]); }else{ objCopy\[key] = obj\[key]; } } } return objCopy;} const copiaPersona = deepCopy(person); console.log(person);console.log(copiaPersona);
En la linea 41, el profe seguramente quiso preguntar por "keyIsArray" porque estamos dentro del bucle "for" evaluando las propiedades de "subject" y cada propiedad está en "key". Pero antes, en la linea 37, hay que agregar una linea en donde asignamos la variable "keyIsArray" de la siguiente manera: const keyIsArray = isArray(subject\[key]); El ejemplo no falla porque en ninguna de las propiedades hay un array. Es solo un pequeño detalle comprensible ante tanta complejidad.
Este es una respuesta al comentario de lgfh, pero no me deja ponerlo abajo así que lo hago aquí: Hola! Tu código está genial. También me puse a jugar con el código del profesor y encontré que se puede simplificar así: ```js function deepCopy(subject) { let copySubject; if (Array.isArray(subject)) { copySubject = []; } else if (typeof subject == "object") { copySubject = {}; } for (key in subject) { if (typeof subject[key] == "object") { copySubject[key] = deepCopy(subject[key]); console.log(copySubject); } else { copySubject[key] = subject[key]; } } return copySubject; } ```Me pareció raro que pudieras dejar por fuera ```js else { copySubject[key] = subject[key]; } ```al final del código porque ahí es precisamente donde se hace la copia. Pero luego en tu código vi que tenías algo que yo no y es: ```js else { return subject; } ```Esto implica que la copia en tu código sucede en un punto distinto al mío, lo confirmé reemplazándolos. Y da igual si dejas ambos porque si la copia ya sucedió en un punto no va a continar ejecutándose para copiar en el siguiente bloque. LoLo que aún no me queda claro, es como tu método y el mío copian los arrays sin el push.
Hola, aquí comparto mi versión del ejercicio con una breve explicación `const originalObject = {` ` name: "José",` ` lastName: "Campos",` ` age: 31,` ` extraData: {` ` countryOfBirth: "Venezuela",` ` countryOfResidence: "Uruguay",` ` }` `};` `function deepCopyWithRecursion(originalObject) {` ` if (typeof originalObject !== 'object' || originalObject === null) {` ` return originalObject;` ` }` ` let objectCopy = Array.isArray(originalObject) ? [] : {};` ` for (let key in originalObject) {` ` if (originalObject.hasOwnProperty(key)) {` ` objectCopy[key] = deepCopyWithRecursion(originalObject[key]);` ` }` ` }` ` return objectCopy;` `}` `const objectCopy = deepCopyWithRecursion(originalObject);` `objectCopy.name = "María";` `objectCopy.lastName = "Betancourt";` `objectCopy.age = 28;` `console.log("Copia con cambios:", objectCopy);` `console.log("Original sin cambios:", originalObject);` Explicación: En el ejercicio previo, llevamos a cabo una copia profunda de un objeto. Inicialmente, definimos un objeto original junto con sus propiedades. Posteriormente, creamos una función para efectuar la copia, empezando por verificar si el objeto original es realmente un objeto mediante el uso de typeof. Si la verificación resulta positiva, procedemos a emplear un bucle for...in para acceder a las propiedades del objeto. Dentro de este bucle, utilizamos el método hasOwnProperty para asegurarnos de acceder únicamente a las propiedades directas del objeto original. Luego, asignamos las mismas propiedades del objeto original al objeto copiado. En el interior de la condición del bucle for...in, realizamos una llamada recursiva a la misma función para cada propiedad del objeto, garantizando de esta manera que también se copien los objetos anidados. Por último, la función devuelve el objeto copiado. Sé que puede parecer confuso. Pero tengo la impresión de que el procedimiento para hacer deep copy con JavaScript siempre es igual, cuando se usa recesión. Primero validamos si es un objeto y luego aplicamos bucles o condicionales para hacer el proceso de copiado.

Recursos de la clase

Por favor revisen la sección de recursos de este curso, toda la info está mal formateada.

☣ Creo que la mejor forma de copiar un objeto con todas sus propiedades y funciones (encadenadas) es usar el Spread operator:

const OBJ = {
	name: 'Diego Rojas',
	curses: ['JavaScript', 'Python'],
	saludar1() { console.log(`Hola me llamo ${this.name}`) }
}

const COPIA = { ...OBJ }

COPIA.saludar1()

Favor actualizar el curso

  const obj = {a:1,b:{a:2},c:[1,2]}

const obj2 = structuredClone(obj) //copia de obj en esta linea temporal

obj.b.a = 4 //cambio en obj

console.log(obj)

console.log(obj2) // contiene a obj antes del cambio

Quizá esto te sirva 😄✌

Si te pasa como a mí que no entendiste el for ni el porqué esa lógica de if's, no es tu culpa, quizá la lógica de la clase no tiene tanta lógica 😅, pero 👉 te dejo mi código para que lo revises.

Esta es una vista panorámica, al ver el código de esta forma (modularizado) me ayuda mucho al estudiar.

Dato: 🚀

El data_copy = [ ] y el data_copy = { } lo agregué de esa manera solo para que entre en la imagen, pero creo que la versión de la clase es mejor. Por otro lado, el for que hice se me hace más sencillo, ya que primero validamos si es objeto, si no, validamos el array y por último al no ser ninguno retornamos la data tal cual entró.

¡Lo mismo pero más cool!!! 👈👀🔥

Código completo en mi GitHub

Enlace de los archivos en GitHub 👈👀

Me robe el código de los aportes de la clase he hice algunas mejoras en la validación de los objetos literales y el for que itera las propiedades(atributos) del objeto studentBase en este caso.

const studentBase = {
  name: undefined,
  email: undefined,
  age: 12,
  approvedCourses: undefined,
  learningPaths: undefined,
  socialMedia: {
    twitter: "Twitter",
    instagram: undefined,
    facebook: undefined,
  },
  hello() {
    console.log("Hello, World!");
  },
};

function isObject(subject) {
  return typeof subject === "object" && !isArray(subject);
}

function isArray(subject) {
  return Array.isArray(subject);
}

function deepCopy(subject) {
  let copy;

  if (isArray(subject)) {
    copy = [];
  } else if (isObject(subject)) {
    copy = {};
  } else {
    return subject;
  }

  for (const key in subject) {
    copy[key] = deepCopy(subject[key]);
  }

  return copy;
}

const COPY = deepCopy(studentBase);

console.log(COPY.age);
console.log(COPY.socialMedia.twitter);
COPY.hello();

Mi algoritmo para el deepCopy de un objeto

const isObject = (elemnt) => {
    return typeof elemnt === "object"; 
};

function deepCopy(subject) {
    let result;

    if (!isObject(subject) || Array.isArray(subject) || subject === null) {
        return subject;
    } 

    if(isObject(subject)) {
        result = {};

        for(let key in subject) {
            if(!isObject(subject[key])) {
                result[key] = subject[key];
                continue;
            }
            if(isObject(subject[key])) {
                result[key] = deepCopy(subject[key]);
            }
        }
    }

    return result;
}

a

De esta forma podemos copiar el objeto sin utilizar recursividad:

 function newObject(element){
  let copyObject;

  if(typeof element == 'object'){
    copyObject = {}
  }else if(Array.isArray(element)){
    copyObject = []
  }else{
    return element
  }

  for (key in element){
    if(typeof element == 'object'){
      copyObject[key] = element[key]
    }else if(Array.isArray(element)){
      copyObject.push(element[key])
    }else{
      copyObject[key] = element[key]
    }
  }

  return copyObject
}

Creo que la solución de la clase es un poco confusa a la hora de entenderla, por lo que decidí implementar mi solución al problema de recursividad:

//Deep copy con recursividad

function isObject(subject){
    return typeof subject === "object";
}

function isArray(subject){
    return Array.isArray(subject);
}

function deepCopy(subject){
    let copySubject;

    const subjectIsObject = isObject(subject);
    const subjectIsArray = isArray(subject);

    if(subjectIsArray){
        copySubject = [];
        for (let i = 0; i < subject.length; i++){
            const keyIsObject = isObject(subject[i]);

            if(keyIsObject){
                copySubject[i] = deepCopy(subject[i]);
            }
            else{
                copySubject.push(subject[i]);
            }
        }
    }
    else if(subjectIsObject){
        copySubject = {};
        for(key in subject){
            const keyIsObject = isObject(subject[key]);

            if(keyIsObject){
                copySubject[key] = deepCopy(subject[key]);
            }
            else{
                copySubject[key] = subject[key];
            }
        }
    }
    else {
        return subject;
    }

    return copySubject;
}

Me gustaria aclarar que un Array es un objeto en JavaScript, por lo que el orden de ejecución del condicional if es importante para que funcione con arreglos y eso se no lo mencionaron en esta clase.

Mi resumen, espero sea entendible.


// ### Deep Copy

//Esta función permitirá copiar un objeto anidado, incluido los métodos

const obj1 = {
    a: "a",
    b: "b",
    c: {
        d: "d",
        e: "e",
    },
    editA() {
        this.a = "AAAAA";
    }
};

//Primero declaramos un par de funciones para validar si la función deepCopy recibira un array, object o string

function isObject(subject) { //verifica si es un objeto
    return typeof subject == "object";
}
function esArray(subject) { //verifica si es un array con el método estático isArray del prototipo Array
    return Array.isArray(subject);
}

function deepCopy(subject) {
    let copySubject; //guardará los datos del objeto que se quiere copiar (en este caso obj1)
    const subjectIsArray = esArray(subject); //verificará si lo que se recibe es un array
    const subjectIsObject = isObject(subject); //verificará si lo que se recibe es un objeto

    if(subjectIsArray) { //según la validación se definirá el tipo de dato de copySubject
        copySubject = [];
    } else if(subjectIsObject) {
        copySubject = {};
    } else {
        return subject; //no se hará nada, devolverá lo mismo si no es array u objeto
    }

for(key in subject) { //validamos cada una de las propiedades dentro del objeto a copiar
    const keyIsObject = isObject(subject[key]); //si las propiedades dentro del objeto tienen como valores a otros objetos
    if(keyIsObject) {
        copySubject[key] = deepCopy(subject[key]); //si una propiedad almacena otro objeto, entonces se ira copiando y pegando las propiedades en copySubject gracias la recursividad deepCopy(subject[key]);
    } else {
            if(subjectIsArray) { //si no es un objeto, será un array que tendrá alguna propiedad dentro del objeto a copiar y se usará el método push
                copySubject.push(subject[key]);
            } else {
                copySubject[key] = subject[key]; //sino es array ni object el valor de la propiedad, se copiará el valor tal como está
            }
        }
    }
    return copySubject; //retorna la variable con todos las propiedades y métodos del objeto original
}

const obj2 = deepCopy(obj1);

console.log(obj2); //{ a: 'a', b: 'b', c: { d: 'd', e: 'e' }, editA: [Function: editA] }

Me parece que JavaScript acaba de implementar un método para hacer un deep copy de un objeto: structuredClone.

https://developer.mozilla.org/en-US/docs/Web/API/structuredClone

Hola, esta es mi versión del deepcopy, espero les guste y puedan ahcer correcciones al código

const obj1 = {
  a: {
    a1: "a",
    a2: "a",
  },
  b: "b",
  edita() {
    this.a.a1 = "aaaaaa";
  },
};

let obj2 = {};

const isObject = (intro) => {
  return typeof intro === "object" ? true : false;
};

const isArray = (intro) => Array.isArray(intro);

const deepCopy = function (objecToCopy, pasteIn) {
  if (isObject(objecToCopy)) {
    pasteIn = {};
  } else if (isArray(objecToCopy)) {
    pasteIn = [];
  } else {
    return objecToCopy;
  }

  for (let item in objecToCopy) {
    if (isObject(objecToCopy[item])) {
      pasteIn[item] = deepCopy(objecToCopy[item], pasteIn[item]);
    } else if (isArray(objecToCopy[item])) {
      pasteIn.push(objecToCopy[item]);
    } else {
      pasteIn[item] = objecToCopy[item];
    }
  }
  return pasteIn;
};

console.log(deepCopy(obj1, obj2));

Muy complicado no entendí nada.

Creo que encontré un problema con la funcion deepCopy

function deepCopy(subject) {
  let copySubject;

  const subjectIsObject = isObject(subject);
  const subjectIsArray = isArray(subject);

  if (subjectIsArray) {
    copySubject = [];
  } else if (subjectIsObject) {
    copySubject = {};
  } else {
    return subject;
  }

  for (let key in subject) {
    const keyIsObject = isObject(subject[key]);

    if (keyIsObject) {
      copySubject[key] = deepCopy(subject[key]);
    } else {
      if (subjectIsArray) {
        copySubject.push(subject[key]);
      } else {
        copySubject[key] = subject[key];
      }
    }
  }

  return copySubject;
}```

Este es el codigo que se hizo en la clase ^


Quiero resaltar que durante la siguiente validación tenemos un problema de logica

for (let key in subject) {
const keyIsObject = isObject(subject[key]);

if (keyIsObject) {
  copySubject[key] = deepCopy(subject[key]);
} else {
  if (subjectIsArray) {
    copySubject.push(subject[key]);
  } else {
    copySubject[key] = subject[key];
  }
}

}```

Si se dan cuenta cada vez que se ejecute este codigo

if (keyIsObject) {
      copySubject[key] = deepCopy(subject[key]);
    } else {
      if (subjectIsArray) {
        copySubject.push(subject[key]);
      } else {
        copySubject[key] = subject[key];
      }

Siempre tendremos como resultado que el key que estemos evaluando sera un instanceof object, la razon es porque los arrays son instacias del prototipo object, entonces la validacion
" if (subjectIsArray)" nunca sera realmente util

me di cuenta de este problem comprobando la efectividad de copiar arrays con metodos como push, el caso es que si la validacion " if (subjectIsArray)" funcionara probablemente la funcion deepCopy estaria rota, porque solo haria una shallow copy de los arrays, la razon por la que funciona correctamente en este momento es porque se aplica la recursividad cuando se valida si es un instanceof object con el metodo isObject cuyo return instanciamos en keyIsObject

en resumen, el codigo funciona bien pero hay un error y si no usáramos las validaciones correctas terminaríamos con shallow copies de los arrays

bajo el mismo contexto, no es necesario que mantengamos esa validación, si lo removemos del codigo igual funciona bien

ejemplo :

function deepCopy(subject) {
  let copySubject;

  const subjectIsObject = isObject(subject);
  const subjectIsArray = isArray(subject);

  if (subjectIsArray) {
    copySubject = [];
  } else if (subjectIsObject) {
    copySubject = {};
  } else {
    return subject;
  }

  for (let key in subject) {
    const keyIsObject = isObject(subject[key]);

    if (keyIsObject) {
      copySubject[key] = deepCopy(subject[key]);
    } else {
      copySubject[key] = subject[key];
    }
  }

  return copySubject;
}```



<code>



Si les cuesta entenderlo hagan la lógica en una libreta con pseudocódigo o diagrama, vean el video y replíquenlo en la libreta sin ver el código de Juan al inicio cuesta pero les asegura que se si le dedican tiempo y paciencia terminaran haciendo hasta su propia solución.

Hay un bug en la funcion isObject, la comparacion devuelve true cuando el argumento es un objeto, pero cuando el argumento es un array devuelve tambien true 😀

Hola!! encontre un pequeño problema, ahora vere como resolverlo pero queria comentarlo aca para ver las soluciones que implementaron, Cuando ejecuto la función isObject

function isObject(subject) {
  return typeof subject == "object";
}

Y pasó un array ejemplo let a = [1,2,5,7,89,23]; , esta tambien me retorna que es true!

Muchachos ya hay una manera mas fácil de copiar obj, sin la referencia en memoria, sino creando un nuevo obj.
Esto sin hacer todo lo que el profe dijo:

const obj1 = {
    a: 'a',
    b: {
        c: 'c',
        d: 'd'
    },
    saludar(){
        return this.a
    }
}

//Spreed Operator
const obj2 = {...obj1} ;

obj2.a = 'Este es obj2'

console.log('obj1', obj1)
console.log('obj2', obj2)
console.log(obj2.saludar());

Exelente clase, quedó mucho más claro el concepto introducido en la clase anterior.

UIff!! como el nombre de la clase mismo lo dice, vaya que esto si estuvo profundo y enredado de entender, como al minuto 6" ya me perdí🙂😥

Estuve buscando en que momento se usaba el spread operator, asi que el spread operator seria un deep copy,

rayos, el profe siempre se equivoca con lo de declarar e inicializar xD

esta clase ha sido bien compleja…

que buena clase, es complejho pero está muy bien explicado y se hace más fácil. Encontré un pequeño error: la función isObject devuelve true cuando le pasamos un array. Lo solucioné para la función deepCopy cambiando un poco la valdiación:

function deepCopy (subject) {
    let copySubject;
    if (isObject(subject) && !isArray(subject)) { //si no es un array pero si es un objeto
        copySubject = {};
        for (key in subject) {
           copySubject[key] = deepCopy(subject[key]) 
        }
    } else if (isArray(subject)) {
        copySubject = [];
        for (key in subject) {
            copySubject.push(subject[key]);
        }
    } else {
        copySubject = subject
    }
    return copySubject
}

Seguro hay mejores maneras de hacerlo, espero que a alguien le sirva igual