Perché la modifica di una matrice in JavaScript influisce sulle copie dell’array?

Ho scritto il seguente codice JavaScript:

var myArray = ['a', 'b', 'c']; var copyOfMyArray = myArray; copyOfMyArray.splice(0, 1); alert(myArray); // alerts ['b','c'] alert(copyOfMyArray); // alerts ['b','c'] var myNumber = 5; var copyOfMyNumber = myNumber; copyOfMyNumber = copyOfMyNumber - 1; alert(myNumber); // alerts 5 alert(copyOfMyNumber); // alerts 4 

Questo codice dichiara una variabile myArray e lo imposta su un valore di matrice. Quindi dichiara una seconda variabile copyOfMyArray e la imposta su myArray . Esegue un’operazione su copyOfMyArray e avvisa sia myArray che copyOfMyArray . In qualche modo, quando copyOfMyArray un’operazione su copyOfMyArray , sembra che la stessa operazione venga eseguita su myArray .

Il codice quindi fa la stessa cosa con un valore numerico: dichiara una variabile myNumber e la imposta su un valore numerico. Quindi dichiara una seconda variabile copyOfMyNumber e la imposta su myNumber . Esegue un’operazione su copyOfMyNumber e avvisa sia myNumber che copyOfMyNumber . Qui, ottengo il comportamento previsto: diversi valori per myNumber e copyOfMyNumber .

Qual è la differenza tra un array e un numero in JavaScript che sembra che la modifica di un array cambi il valore di una copia dell’array, in cui la modifica di un numero non modifica il valore di una copia del numero?

Sto indovinando che per qualche motivo, la matrice è riferita per riferimento e il numero per valore, ma perché? Come posso sapere quale comportamento aspettarsi con altri oggetti?

Un array in JavaScript è anche un object e le variabili contengono solo un riferimento a un object, non l’object stesso. Quindi entrambe le variabili hanno un riferimento allo stesso object.

Il tuo confronto con l’esempio del numero non è corretto btw. Assegnare un nuovo valore a copyOfMyNumber . Se assegni un nuovo valore a copyOfMyArray , non cambierà neanche myArray .

Puoi creare una copia di un array usando slice [docs] :

 var copyOfMyArray = myArray.slice(0); 

Nota che questo restituisce solo una copia superficiale , cioè gli oggetti all’interno dell’array non saranno clonati.

Bene, l’unica risposta ansible – e quella giusta – è che in realtà non stai copiando l’array. Quando scrivi

 var copyOfArray = array; 

stai assegnando un riferimento allo stesso array in un’altra variabile. Stanno entrambi puntando allo stesso object, in altre parole.

Quindi tutti qui hanno fatto un ottimo lavoro nel spiegare perché questo sta accadendo: volevo solo eliminare una riga e farvi sapere come sono riuscito a sistemarlo – piuttosto facilmente:

 thingArray = ['first_thing', 'second_thing', 'third_thing'] function removeFirstThingAndPreserveArray(){ var copyOfThingArray = [...thingArray] copyOfThingArray.shift(); return copyOfThingArray; } 

Questo sta usando … la syntax di diffusione.

Spread Syntax Source

EDIT: Per quanto riguarda il motivo di questo, e per rispondere alla tua domanda:

Qual è la differenza tra un array e un numero in JavaScript che sembra che la modifica di un array cambi il valore di una copia dell’array, in cui la modifica di un numero non modifica il valore di una copia del numero?

La risposta è che in JavaScript, gli array e gli oggetti sono mutabili , mentre stringhe e numeri e altri primitivi sono immutabili . Quando facciamo un incarico come:

var myArray = ['a', 'b', 'c']; var copyOfMyArray = myArray;

copyOfMyArray è davvero solo un riferimento a myArray, non una copia effettiva.

Consiglierei questo articolo, quali sono le strutture di dati immutabili e mutevoli? , per approfondire l’argomento.

Glossario MDN: mutabile

Clonazione di oggetti –

Un loop / array.push produce un risultato simile a array.slice(0) o array.clone() . I valori vengono tutti passati per riferimento, ma poiché molti tipi di dati primitivi sono immutabili , le operazioni successive producono il risultato desiderato: un “clone”. Questo non è vero per gli oggetti e gli array, ovviamente, che consentono la modifica del riferimento originale (sono tipi mutabili).

Prendi il seguente esempio:

 const originalArray = [1, 'a', false, {foor: 'bar'}] const newArray = []; originalArray.forEach((v, i) => { newArray.push(originalArray[i]); }); newArray[0] = newArray[0] + 1; newArray[1] = 'b'; newArray[2] = true; newArray[3] = Object.assign(newArray[3], {bar: 'foo'}); 

Le operazioni eseguite sugli indici newArray producono tutti il ​​risultato desiderato, ad eccezione del finale (object), che, poiché è copiato per riferimento, modificherà anche l’array originale [3].

https://jsfiddle.net/7ajz2m6w/

Si noti che array.slice(0) and array.clone() soffrono di questa stessa limitazione.

Un modo per risolverlo è di clonare efficacemente l’object durante la sequenza push:

 originalArray.forEach((v, i) => { const val = (typeof v === 'object') ? Object.assign({}, v) : v; newArray.push(val); }); 

https://jsfiddle.net/e5hmnjp0/

Saluti

In JS, l’operatore “=” copia il puntatore sull’area di memoria dell’array. Se vuoi copiare un array in un altro devi usare la funzione Clone.

Per gli interi è diverso perché sono un tipo primitivo.

S.

Crea un filtro dell’array originale in arrayCopy. In questo modo le modifiche al nuovo array non influiscono sull’array originale.

 var myArray = ['a', 'b', 'c']; var arrayCopy = myArray.filter(function(f){return f;}) arrayCopy.splice(0, 1); alert(myArray); // alerts ['a','b','c'] alert(arrayCopy); // alerts ['b','c'] 

Spero che sia d’aiuto.

Tutto viene copiato per riferimento eccetto i tipi di dati primitivi (stringhe e numeri IIRC).

Non hai copie.
Hai più variabili che contengono lo stesso array.

Allo stesso modo, hai più variabili con lo stesso numero.

Quando scrivi copyOfMyNumber = ... , stai inserendo un nuovo numero nella variabile.
È come scrivere copyOfMyArray = ...

Quando scrivi copyOfMyArray.splice , stai modificando l’array originale .
Questo non è ansible con i numeri perché i numeri sono immutabili e non possono essere modificati,

È ansible aggiungere alcuni errori di gestione a seconda dei casi e utilizzare qualcosa di simile alla seguente funzione per risolvere il problema. Si prega di commentare per eventuali bug / problemi / idee di efficienza.

 function CopyAnArray (ari1) { var mxx4 = []; for (var i=0;i 

Un array o un object in javascript mantiene sempre lo stesso riferimento a meno che non si cloni o si copi. Ecco un exmaple:

http://plnkr.co/edit/Bqvsiddke27w9nLwYhcl?p=preview

 // for showing that objects in javascript shares the same reference var obj = { "name": "a" } var arr = []; //we push the same object arr.push(obj); arr.push(obj); //if we change the value for one object arr[0].name = "b"; //the other object also changes alert(arr[1].name); 

Per il clone dell’object, possiamo usare .clone () in jquery e angular.copy (), queste funzioni creeranno un nuovo object con altro riferimento. Se conosci più funzioni per farlo, per favore dimmi, grazie!

Trovo questo il modo più semplice per creare un clone profondo di un object o array:

 const objectThatIWantToClone = { foo: 'bar'}; const clone = JSON.parse(JSON.stringify(objectThatIWantToClone)); 

Stringendola, ne facciamo una copia che è immutabile e che possiamo convertire in JSON.

https://codepen.io/Buts/pen/zWdVyv

Un altro approccio per copiare l’array in una variabile temporanea può essere tipizzazione / modifica dell’array in stringa e quindi recuperarlo.

Per esempio

 var a = [1,2,3]; typeof(a) (this will give "object") var b = JSON.stringify(a); typeof(b) (this will give "string"); b = JSON.parse(b); typeOf(b) (this will give "object") 

e ora chnage in valore di b non si rifletterà su a

La tua risposta è qui

 var myArray = ['a', 'b', 'c']; var copyOfMyArray = myArray.slice(); 

Fondamentalmente, l’operazione slice () clona l’array e restituisce il riferimento al nuovo array.

 copyOfMyArray.splice(0, 1); alert(myArray); // alerts ['a', 'b', 'c'] alert(copyOfMyArray); // alerts ['b','c']