Tarde o temprano, uno se encuentra con un fenómeno desconcertante en javaScript que, al menos a mí, me trajo de cabeza en su día. A veces nos interesa conservar el valor original de algo para restaurarlo o cotejarlo o alguna que otra acción similar, así que sacamos una copia de trabajo.
var valorOriginal = 1;
var valorTrabajo = valorOriginal;
valorTrabajo += 2;
...
Pero si tratamos de hacer esto mismo con un array o un json nos encontraremos con un problema, pues los cambios que se hagan en la copia también afectan al valor original.
var arrayOriginal = ['lagarto', 'mandril', 'hipopótamo'];
var arrayCopia = arrayOriginal;
arrayCopia[1] = 'tucán';
console.log( arrayOriginal[1] ) // tucán oO!!!
var jsonOriginal = ['orquídea', 'cactus', 'mandrágora'];
var jsonCopia = jsonOriginal;
jsonCopia[1] = 'loto';
console.log( jsonOriginal[1] ) // loto oO!!!
Esto sucede porque en javaScript existen dos tipos de datos, primitivos y objetos, y cada cual se guarda de manera distinta en memoria. Los datos primitivos son las cadenas, los números, los valores booleanos, undefined y null; y, por decirlo de alguna manera, cada cual se guarda en su propio sitio.
El valor del resto de cosas, es decir, de los arrays, las funciones y los objetos se guardan por referencia; es decir que cuando sacamos una copia de uno, esa copia sigue «apuntando» al sitio original. Entonces, ¿cómo podemos sacar una copia de un array o un json y trabajarla sin alterar el original? Carlos Benítez de EtnaSoft nos da algunas soluciones.
Para copiar un array basta con emplear el método slice() sin parámetros:
var arrayOriginal = ['lagarto', 'mandril', 'hipopótamo'];
var arrayCopia = arrayOriginal.slice();
arrayCopia[1] = 'tucán';
console.log( arrayOriginal[1] ) // mandril : )
Para los jsons tenemos tres posibilidades. Si estamos con jQuery, basta con utilizar el método extend():
var jsonCopia = $.extend({}, jsonOriginal);
Otra posibilidad es recurrir a esta función que propone Carlos Benítez:
function clone( obj ) {
if ( obj === null || typeof obj !== 'object' ) {
return obj;
}
var temp = obj.constructor();
for ( var key in obj ) {
temp[ key ] = clone( obj[ key ] );
}
return temp;
}
var jsonCopia = clone( jsonOriginal );
Y la tercera solución que propone este autor es pasar el json original por un stringfly, es decir, convertirlo en cadena, y luego parsearlo. Mola : )