Delete copied array item without deleting the item from its source - VueJS
I would like to clone a list of numbers and be able to manipulate that cloned list without making change to the source, but in the following situation when I delete the item from the cloned array it deletes the source.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<ul>
<h3>Lista Origem</h3>
<li v-for="item in listaOriginal">
{{item}}
</li>
</ul>
<ul>
<h3>Lista Clone</h3>
<li v-for="item in listaClone">
{{item}}
</li>
</ul>
<button @click="clonaLista">Clonar Lista</button>
<button @click="removerItem">Remover item do Clone</button>
</div>
<script>
const vue = new Vue({
el: "#app",
data: {
listaOriginal: [1, 2, 3],
listaClone: []
},
methods: {
clonaLista() {
this.listaClone = this.listaOriginal
},
removerItem() {
this.listaClone.pop()
}
}
})
</script>
</body>
</html>
3 answers
Rodolfo this is because the Array is a reference type. When you say that listaClone = listaOriginal
both variables point to the same array. To solve use a spread to clone effectively:
this.listaClone = [...this.listaOriginal];
There are several ways to copy an array, but you need to know if you want a shallow copy (shallow copy) or a deep copy (deep copy) 1.
If you are just working with primitive types like Number
, String
or Boolean
will not make a difference you use a shallow or deep copy. From the moment your array contains other arrays or objects, you'll be working with references if you just copy those references you will be making a shallow copy, but if you make a copy of the object to the new array, you will be making a deep copy.
let array = [1, 2, 3, 4];
let copia = array; // cópia da referência
copia.push(5);
// Como `array` e `copia` referenciam o mesmo
// objeto em memória, alterações feitas em
// ambos inferem no mesmo objeto
console.log(array);
// [1, 2, 3, 4, 5]
Some methods to create shallow Copy
-
Array.slice
(#docs & compatibility )David Walsh posted in this article a way to make a shallow copy using the method
Array.slice
. The big advantage of this method is its compatibility with old browsers.let array = [1, 2, 3]; let copia = array.slice(0); copia.push(4); console.log(array); // [1, 2, 3] console.log(copia); // [1, 2, 3, 4]
-
Spread operator ( # docs & compatibility )
let array = [1, 2, 3]; let copia = [...array];
-
For loop
let array = [1, 2, 3]; let copia = []; for (let i=0, l=array.length ; i<l ; i++) { copia.push(array[i]); }
-
Array.map
(#docs & compatibility )let array = [1, 2, 3]; let copia = array.map(x => x);
Methods for creating deep copy
-
JSON.stringify
eJSON.parse
(compatibility )You can use
JSON.stringify
eJSON.parse
to create deep copies of objects.let array = [[1], [2], [3]]; let copia = JSON.parse(JSON.stringify(array)); copia[0].push(1.5); console.log(array); // [[1], [2], [3]] console.log(copia); // [[1, 1.5], [2], [3]]
-
_.cloneDeep
(#docs )If you are using the lodash library, you can use the function
_.cloneDeep
.let array = [[1], [2], [3]]; let copia = _.cloneDeep(array); copia[0].push(1.5); console.log(array); // [[1], [2], [3]] console.log(copia); // [[1, 1.5], [2], [3]]
This article mentions some other methods you can use to create shallow copies.
You can get a copy of the array by doing this:
let array = [1, 2, 3];
let copy = array.slice()
The way you did was not copying the array, but referencing the same. :)