Extraer y Modificar Partes de Arreglos: slice() y splice()
Formas de Copiar Arreglos en JavaScript
🤔 ¿Por Qué Copiar un Arreglo?
A veces, queremos trabajar con los datos de un arreglo sin modificar el original. Si simplemente asignamos un arreglo a otra variable, no estamos creando una copia, sino que ambas variables apuntarán al mismo arreglo en la memoria.
let original = [1, 2, 3];let referencia = original; // NO es una copia
referencia.push(4);
console.log(original); // Muestra [1, 2, 3, 4] ¡El original fue modificado!console.log(referencia); // Muestra [1, 2, 3, 4]
Para evitar esto, necesitamos crear una copia independiente.
📋 Copias Superficiales (Shallow Copies)
La mayoría de los métodos integrados crean copias superficiales. Esto significa que copian los elementos del primer nivel del arreglo. Si esos elementos son valores primitivos (números, strings, booleanos), se copian por valor y son independientes. Pero si los elementos son objetos o arreglos, se copia la referencia a esos objetos/arreglos, no los objetos/arreglos en sí.
1. Usando slice()
Como vimos, llamar a slice()
sin argumentos crea una copia superficial de todo el arreglo.
let numeros = [10, 20, 30];let copiaNumeros = numeros.slice();
copiaNumeros.push(40);
console.log(numeros); // Muestra [10, 20, 30] (Original intacto)console.log(copiaNumeros); // Muestra [10, 20, 30, 40]
2. Usando el Operador Spread (...
)
El operador Spread es una forma moderna y muy legible de crear copias superficiales.
let colores = ["Rojo", "Verde", "Azul"];let copiaColores = [...colores];
copiaColores[0] = "Morado";
console.log(colores); // Muestra ["Rojo", "Verde", "Azul"]console.log(copiaColores); // Muestra ["Morado", "Verde", "Azul"]
3. Usando Array.from()
Array.from()
crea una nueva instancia de Array a partir de un objeto iterable (como otro arreglo).
let herramientas = ["Martillo", "Sierra"];let copiaHerramientas = Array.from(herramientas);
copiaHerramientas.pop(); // Quita "Sierra"
console.log(herramientas); // Muestra ["Martillo", "Sierra"]console.log(copiaHerramientas); // Muestra ["Martillo"]
El Problema de las Copias Superficiales con Objetos/Arreglos Anidados
Si el arreglo contiene objetos o más arreglos, la copia superficial solo copia las referencias:
let originalAnidado = [{ id: 1 }, { id: 2 }];let copiaSuperficial = [...originalAnidado];
// Modificamos un objeto DENTRO de la copiacopiaSuperficial[0].id = 99;
// ¡El cambio se refleja en el original también!console.log(originalAnidado[0].id); // Muestra 99console.log(copiaSuperficial[0].id); // Muestra 99
⚠️ ¡Cuidado! Con arreglos anidados u objetos dentro de arreglos, slice()
,
...
y Array.from()
no crean copias independientes de esos elementos
internos.
🧱 Copias Profundas (Deep Copies)
Para crear una copia completamente independiente, incluyendo objetos y arreglos anidados, necesitamos una copia profunda. No hay un método integrado simple y universal para esto, pero hay técnicas comunes:
1. Usando JSON.stringify()
y JSON.parse()
Una forma común (con limitaciones) es convertir el arreglo a un string JSON y luego de vuelta a un objeto/arreglo JavaScript.
let originalProfundo = [{ valor: 10 }, [{ sub: 20 }]];let copiaProfunda = JSON.parse(JSON.stringify(originalProfundo));
// Modificamos un objeto anidado en la copiacopiaProfunda[1][0].sub = 500;
// El original NO se ve afectadoconsole.log(originalProfundo[1][0].sub); // Muestra 20console.log(copiaProfunda[1][0].sub); // Muestra 500
Limitaciones: Este método no funciona bien con ciertos tipos de datos como Date
, RegExp
, Map
, Set
, funciones, o undefined
, ya que se pierden o transforman durante la serialización JSON.
2. Usando structuredClone()
(Moderno)
La forma más moderna y robusta es usar la función global structuredClone()
.
let datosOriginales = [{ fecha: new Date() }, { set: new Set([1, 2]) }];let copiaEstructurada = structuredClone(datosOriginales);
// Modificamos el Set en la copiacopiaEstructurada[1].set.add(3);
// El original NO se ve afectadoconsole.log(datosOriginales[1].set); // Muestra Set(2) { 1, 2 }console.log(copiaEstructurada[1].set); // Muestra Set(3) { 1, 2, 3 }
💡 structuredClone()
es la mejor opción moderna para crear copias
profundas, ya que maneja más tipos de datos que el truco de JSON.
☝️🤓
🏋️♂️ Ejercicio
- Crea un arreglo
miArray = [5, 10, 15]
. 2. Crea una referencia llamadarefArray
asignándolemiArray
. 3. Crea una copia superficial llamadacopiaArray
usando el operador Spread. 4. ModificarefArray
agregando el número 20 al final (push(20)
). 5. ModificacopiaArray
cambiando el primer elemento a99
(copiaArray[0] = 99
). 6. Muestra por consolamiArray
,refArray
ycopiaArray
. Explica por quémiArray
cambió en un caso pero no en el otro.
🏋️♂️ Ejercicio
Dado el arreglo: let datos = [{ nombre: "Alice" }, { nombre: "Bob" }];
- Crea una copia superficial
copia1
usandoslice()
. - Crea una copia profunda
copia2
usandostructuredClone()
. - Cambia el nombre del primer objeto en
copia1
a “Charlie” (copia1[0].nombre = "Charlie"
). - Cambia el nombre del segundo objeto en
copia2
a “David” (copia2[1].nombre = "David"
). - Muestra por consola el arreglo
datos
original. ¿Cuál de las modificaciones (Charlie
oDavid
) afectó al original y por qué?
🚀 Extra
Investiga sobre: 1. Las limitaciones exactas del método
JSON.parse(JSON.stringify())
para copias profundas (qué tipos de datos no
maneja bien). 2. Bibliotecas de JavaScript populares (como Lodash) que ofrecen
funciones para realizar copias profundas (ej. _.cloneDeep()
). ¿Qué ventajas
ofrecen sobre structuredClone()
o el método JSON? 3. ¿Qué es la “copia por
valor” vs “copia por referencia” en JavaScript?