Napisałem następujący 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
Ten kod deklaruje zmienną myArray
i ustawia ją na wartość tablicy. Następnie deklaruje drugą zmienną copyOfMyArray
i ustawia ją na myArray
. Wykonuje operację na, copyOfMyArray
a następnie ostrzega zarówno myArray
i copyOfMyArray
. W jakiś sposób, gdy wykonuję operację na copyOfMyArray
, wydaje się, że ta sama operacja jest wykonywana na myArray
.
Następnie kod robi to samo z wartością liczbową: deklaruje zmienną myNumber
i ustawia ją na wartość liczbową. Następnie deklaruje drugą zmienną copyOfMyNumber
i ustawia ją na myNumber
. Wykonuje operację na, copyOfMyNumber
a następnie ostrzega zarówno myNumber
i copyOfMyNumber
. Tutaj otrzymuję oczekiwane zachowanie: różne wartości dla myNumber
i copyOfMyNumber
.
Jaka jest różnica między tablicą a liczbą w JavaScript, że wydaje się, że zmiana tablicy zmienia wartość kopii tablicy, podczas gdy zmiana liczby nie zmienia wartości kopii liczby?
Zgaduję, że z jakiegoś powodu tablica jest określana przez odniesienie, a liczba przez wartość, ale dlaczego? Skąd mogę wiedzieć, jakiego zachowania należy się spodziewać w przypadku innych obiektów?
źródło
myArray.slice(0);
bezpośrednio w tym kontekście?Cóż, jedyną możliwą odpowiedzią - i właściwą - jest to, że w rzeczywistości nie kopiujesz tablicy. Kiedy piszesz
var copyOfArray = array;
przypisujesz odwołanie do tej samej tablicy do innej zmiennej. Innymi słowy, oba wskazują na ten sam obiekt.
źródło
5
są zawsze równe.Więc wszyscy tutaj wykonali świetną robotę, wyjaśniając, dlaczego tak się dzieje - chciałem tylko rzucić uwagę i dać ci znać, jak udało mi się to naprawić - całkiem łatwo:
thingArray = ['first_thing', 'second_thing', 'third_thing'] function removeFirstThingAndPreserveArray(){ var copyOfThingArray = [...thingArray] copyOfThingArray.shift(); return copyOfThingArray; }
To jest przy użyciu składni ... spread.
Źródło składni spreadu
EDYTUJ: Jeśli chodzi o powód tego i odpowiedz na twoje pytanie:
Odpowiedź jest taka, że w JavaScript tablice i obiekty są zmienne , podczas gdy łańcuchy i liczby oraz inne prymitywy są niezmienne . Kiedy wykonujemy zadanie takie jak:
copyOfMyArray to tak naprawdę tylko odniesienie do myArray, a nie rzeczywista kopia.
Polecam ten artykuł, Czym są niezmienne i zmienne struktury danych? , aby zagłębić się w temat.
Glosariusz MDN: Mutable
źródło
Klonowanie obiektów -
A
loop / array.push
daje podobny wynik doarray.slice(0)
lubarray.clone()
. Wszystkie wartości są przekazywane przez odwołanie, ale ponieważ większość pierwotnych typów danych jest niezmienna , kolejne operacje dają pożądany wynik - „klon”. Nie dotyczy to oczywiście obiektów i tablic, które pozwalają na modyfikację oryginalnego odniesienia (są to typy zmienne).Weźmy następujący przykład:
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'});
Wszystkie operacje wykonywane na indeksach newArray dają pożądany wynik, z wyjątkiem finału (obiektu), który, ponieważ jest kopiowany przez odniesienie, powoduje również mutację tablicy originalArray [3].
https://jsfiddle.net/7ajz2m6w/
Zauważ, że
array.slice(0)
and array.clone()
cierpi na to samo ograniczenie.Jednym ze sposobów rozwiązania tego problemu jest skuteczne klonowanie obiektu podczas sekwencji wypychania:
originalArray.forEach((v, i) => { const val = (typeof v === 'object') ? Object.assign({}, v) : v; newArray.push(val); });
https://jsfiddle.net/e5hmnjp0/
Twoje zdrowie
źródło
W JS operator „=” kopiuje wskaźnik do obszaru pamięci tablicy. Jeśli chcesz skopiować tablicę do innej, musisz użyć funkcji Clone.
Dla liczb całkowitych jest inny, ponieważ są typem pierwotnym.
S.
źródło
Wszystko jest kopiowane przez odwołanie, z wyjątkiem pierwotnych typów danych (łańcuchy i liczby IIRC).
źródło
Nie masz żadnych kopii.
Masz wiele zmiennych przechowujących tę samą tablicę.
Podobnie masz wiele zmiennych o tej samej liczbie.
Kiedy piszesz
copyOfMyNumber = ...
, wstawiasz nową liczbę do zmiennej.To jak pisanie
copyOfMyArray = ...
.Kiedy piszesz
copyOfMyArray.splice
, modyfikujesz oryginalną tablicę .Nie jest to możliwe w przypadku liczb, ponieważ liczby są niezmienne i nie można ich modyfikować,
źródło
Utwórz filtr oryginalnej tablicy w arrayCopy. Więc zmiany w nowej tablicy nie wpłyną na oryginalną tablicę.
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']
Mam nadzieję, że to pomoże.
źródło
Problem z płytką kopią polega na tym, że wszystkie obiekty nie są klonowane, zamiast tego otrzymują referencje, więc array.slice (0) będzie działać dobrze tylko z tablicą literałów, ale nie zrobi płytkiej kopii z tablicą obiektów. W takim przypadku jeden sposób to ...
var firstArray = [{name: 'foo', id: 121}, {name: 'zoo', id: 321}]; var clonedArray = firstArray.map((_arrayElement) => Object.assign({}, _arrayElement)); console.log(clonedArray); // [{name: 'foo', id: 121}, {name: 'zoo', id: 321}] // shallow copy
źródło
Możesz dodać obsługę błędów w zależności od przypadków i użyć czegoś podobnego do poniższej funkcji, aby rozwiązać problem. Prosimy o komentarz w przypadku jakichkolwiek błędów / problemów / pomysłów dotyczących wydajności.
function CopyAnArray (ari1) { var mxx4 = []; for (var i=0;i<ari1.length;i++) { var nads2 = []; for (var j=0;j<ari1[0].length;j++) { nads2.push(ari1[i][j]); } mxx4.push(nads2); } return mxx4; }
źródło
Tablica lub obiekt w javascript zawsze zawiera to samo odniesienie, chyba że sklonujesz lub skopiujesz. Oto przykład:
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);
Do klonowania obiektu możemy użyć .clone () w jquery i angular.copy (), te funkcje utworzą nowy obiekt z innym odniesieniem. Jeśli znasz więcej funkcji do tego, powiedz mi, dzięki!
źródło