2013-01-23 12 views
22

Ho letto qui molte risposte relative a "in base al valore" e "in base al riferimento" che passano per l'invio di matrici a funzioni javascript. Tuttavia, ho un problema nell'invio di un array a una funzione e l'inalteramento della matrice originale. Questo esempio illustra il problema:Javascript passa array a funzioni in base al valore, lasciando inalterato l'array originale

function myFunction(someArray) 
{ 
// any function that makes an array based on a passed array; 
// someArray has two dimensions; 
// I've tried copying the passed array to a new array like this (I've also used 'someArray' directly in the code); 

funcArray = new Array(); 
funcArray = someArray; 

var i = 0; 

    for(i=0; i<funcArray.length; i++) 
    { 
    funcArray[i].reverse; 
    } 

return funcArray; 

} 

Non riesco a capire perché qualsiasi cosa in questa funzione dovrebbe alterare l'array originale.

richiamare questa funzione modifica direttamente la matrice originale se la chiamata funzione è assegnata a un nuovo array:

myArray = [["A","B","C"],["D","E","F"],["G","H","I"]]; 
anotherArray = new Array(); 

anotherArray = myFunction(myArray); 
// myArray gets modified!; 

Ho provato ad utilizzare .valueOf() per inviare il primitivo:

anotherArray = myFunction(myArray.valueOf()); 
// myArray gets modified!; 

I Ho anche provato a spezzare l'elemento array down per elemento e sottoelemento per sub-elemento e assegnare tutto a un nuovo array 2-d e l'array originale viene ancora modificato.

Ho anche unito i sottoelementi a una stringa, li ho elaborati, li ho divisi in array e l'array originale viene ancora modificato.

Per favore, qualcuno sa come posso passare i valori dell'array a una funzione e non avere la matrice passata cambiare?

+0

Mi dispiace, ho dimenticato di menzionare che il metodo slice non fa alcuna differenza. Ho visto questo accennato e provato, ma non smette di cambiare l'array originale (nemmeno .valueOf() che dovrebbe ridurre il contenuto dell'array alla primitiva) –

+0

Ho esplorato l'idea di slice() ancora e ancora il problema sta nel fatto che è un array 2-d. Se affetto l'array esterno, non fa alcuna differenza, l'array originale viene ancora modificato. Tuttavia, se divido ogni sub-array, funziona! Ho impostato un ciclo per ciascun elemento esterno e assegnato la sua sezione all'elemento esterno di un nuovo array. –

risposta

32

Dentro la funzione c'è questo:

funcArray = new Array(); 
funcArray = someArray; 

Questo non sarà effettivamente copiare someArray ma invece fare riferimento a esso, che è il motivo per cui l'array originale viene modificato.

È possibile utilizzare Array.slice() per creare una cosiddetta copia superficiale dell'array.

var funcArray = someArray.slice(0); 

L'array originale sarà inalterato, ma ciascuno dei suoi elementi sarebbe ancora riferimento le voci corrispondenti nell'array originale. Per "clonazione profonda" è necessario farlo in modo ricorsivo; il modo più efficace è discusso nella seguente domanda:

What is the most efficient way to deep clone an object in JavaScript?

Btw, ho aggiunto var prima funcArray. Fare così lo rende locale alla funzione invece di essere una variabile globale.

+0

Grazie, come per il mio secondo commento, slice() lo fa funzionare ma solo se applicato a ciascun elemento esterno dell'array 2-d eseguendo il ciclo. –

1

Una variabile che punta a un array è un riferimento ad esso. Quando passi un array, stai copiando questo riferimento.

È possibile eseguire una copia superficiale con slice(). Se si desidera una copia di profondità completa, quindi ricorrere agli oggetti secondari, tenendo presente gli avvertimenti durante la copia di alcuni oggetti.

+0

Grazie, sì, ho trovato se ho tagliato ogni elemento esterno a sua volta ora funziona. –

0

Una soluzione generica sarebbe ...

// Use the JSON parse to clone the data. 
function cloneData(data) { 
    // Convert the data into a string first 
    var jsonString = JSON.stringify(data); 

    // Parse the string to create a new instance of the data 
    return JSON.parse(jsonString); 
} 

// An array with data 
var original = [1, 2, 3, 4]; 

function mutate(data) { 
    // This function changes a value in the array 
    data[2] = 4; 
} 

// Mutate clone 
mutate(cloneData(original)); 

// Mutate original 
mutate(original); 

Questo funziona per gli oggetti e gli array.

Molto efficace quando è necessaria la clonazione profonda o non si conosce il tipo.

esempio la clonazione profonda ...

var arrayWithObjects = [ { id: 1 }, { id: 2 }, { id: 3 } ]; 

function mutate(data) { 
    // In this case a property of an object is changed! 
    data[1].id = 4; 
} 

// Mutates a (DEEP) cloned version of the array 
mutate(cloneData(arrayWithObjects)); 

console.log(arrayWithObjects[1].id) // ==> 2 

Avvertenze

  • Uso del parser JSON per clonare non è l'opzione più performante!

  • Non clone funzioni solo JSON supportati i tipi di dati

  • Non può clonare i riferimenti circolari

+0

Questo sembra completo ma non ho familiarità con JSON. Sembra che dovrei investire per saperne di più. Il problema è ora risolto eseguendo il ciclo di ciascun elemento esterno e assegnando il suo .slice() a un nuovo array. –

+0

Nel tuo esempio, "cloneData" non dovrebbe essere solo "clone" (o viceversa)? – neemzy

+0

@neemzy corretto! Lo ha cambiato –

7

Fare una copia della matrice che è possibile utilizzare.

Un modo semplice per farlo è quello di utilizzare var clone = original.slice(0);

+0

Grazie. Ho trovato che slice funziona solo se applicato a ciascun elemento esterno tramite il loop: newArray [i] = array [i] .slice() –

0

Se avete bisogno di fare questo con un oggetto, provare questo trucco fantasia ...

MY_NEW_OBJECT = JSON.parse(JSON.stringify(MY_OBJECT)); 
-1
var aArray = [0.0, 1.0, 2.0]; 
var aArrayCopy = aArray.concat(); 
aArrayCopy[0] = "A changed value."; 
console.log("aArray: "+aArray[0]+", "+aArray[1]+", "+aArray[2]); 
console.log("aArrayCopy: "+aArrayCopy[0]+", "+aArrayCopy[1]+", "+aArrayCopy[2]); 

Questa risposta è stato modificato . Inizialmente presentai che l'operatore new gestiva la soluzione, ma in seguito riconobbi quell'errore. Invece, ho optato per utilizzare il metodo concat() per creare una copia. La risposta originale non ha mostrato l'intero array, quindi l'errore è stato inavvertitamente nascosto. Il nuovo output mostrato di seguito dimostrerà che questa risposta funziona come previsto.

aArray: 0, 1, 2 
aArrayCopy: A changed value., 1, 2 
+0

Quel codice non fa quello che pensi, con 'new Array (aArray)' stai creando un nuovo array in cui il primo elemento è 'aArray', non facendo una copia dell'array originale, registra gli array completi invece del primo elemento e vedrai la differenza. –

+0

Grazie Alberto. Eri pronto a rispondere e correggere. Uso di 'new Array (someArray);' impostare la lunghezza su 1 e impostare quel primo elemento sul riferimento dell'arrray passato senza un'assegnazione di valore appropriata per elemento come previsto per un valore pass-by-value. Ho usato molto recentemente Float32Array e ho dovuto riapprendere che l'array di base non costruisce allo stesso modo. Il mio output di prova non ha identificato l'errore. Ora risulta correttamente l'intera copia dell'array. –

Problemi correlati